kiln-ai 0.8.1__py3-none-any.whl → 0.12.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.

Files changed (88) hide show
  1. kiln_ai/adapters/__init__.py +7 -7
  2. kiln_ai/adapters/adapter_registry.py +81 -10
  3. kiln_ai/adapters/data_gen/data_gen_task.py +21 -3
  4. kiln_ai/adapters/data_gen/test_data_gen_task.py +23 -3
  5. kiln_ai/adapters/eval/base_eval.py +164 -0
  6. kiln_ai/adapters/eval/eval_runner.py +267 -0
  7. kiln_ai/adapters/eval/g_eval.py +367 -0
  8. kiln_ai/adapters/eval/registry.py +16 -0
  9. kiln_ai/adapters/eval/test_base_eval.py +324 -0
  10. kiln_ai/adapters/eval/test_eval_runner.py +640 -0
  11. kiln_ai/adapters/eval/test_g_eval.py +497 -0
  12. kiln_ai/adapters/eval/test_g_eval_data.py +4 -0
  13. kiln_ai/adapters/fine_tune/base_finetune.py +5 -1
  14. kiln_ai/adapters/fine_tune/dataset_formatter.py +310 -65
  15. kiln_ai/adapters/fine_tune/fireworks_finetune.py +47 -32
  16. kiln_ai/adapters/fine_tune/openai_finetune.py +12 -11
  17. kiln_ai/adapters/fine_tune/test_base_finetune.py +19 -0
  18. kiln_ai/adapters/fine_tune/test_dataset_formatter.py +472 -129
  19. kiln_ai/adapters/fine_tune/test_fireworks_tinetune.py +114 -22
  20. kiln_ai/adapters/fine_tune/test_openai_finetune.py +125 -14
  21. kiln_ai/adapters/ml_model_list.py +434 -93
  22. kiln_ai/adapters/model_adapters/__init__.py +18 -0
  23. kiln_ai/adapters/model_adapters/base_adapter.py +250 -0
  24. kiln_ai/adapters/model_adapters/langchain_adapters.py +309 -0
  25. kiln_ai/adapters/model_adapters/openai_compatible_config.py +10 -0
  26. kiln_ai/adapters/model_adapters/openai_model_adapter.py +289 -0
  27. kiln_ai/adapters/model_adapters/test_base_adapter.py +199 -0
  28. kiln_ai/adapters/{test_langchain_adapter.py → model_adapters/test_langchain_adapter.py} +105 -97
  29. kiln_ai/adapters/model_adapters/test_openai_model_adapter.py +216 -0
  30. kiln_ai/adapters/{test_saving_adapter_results.py → model_adapters/test_saving_adapter_results.py} +80 -30
  31. kiln_ai/adapters/{test_structured_output.py → model_adapters/test_structured_output.py} +125 -46
  32. kiln_ai/adapters/ollama_tools.py +0 -1
  33. kiln_ai/adapters/parsers/__init__.py +10 -0
  34. kiln_ai/adapters/parsers/base_parser.py +12 -0
  35. kiln_ai/adapters/parsers/json_parser.py +37 -0
  36. kiln_ai/adapters/parsers/parser_registry.py +19 -0
  37. kiln_ai/adapters/parsers/r1_parser.py +69 -0
  38. kiln_ai/adapters/parsers/test_json_parser.py +81 -0
  39. kiln_ai/adapters/parsers/test_parser_registry.py +32 -0
  40. kiln_ai/adapters/parsers/test_r1_parser.py +144 -0
  41. kiln_ai/adapters/prompt_builders.py +193 -49
  42. kiln_ai/adapters/provider_tools.py +91 -36
  43. kiln_ai/adapters/repair/repair_task.py +18 -19
  44. kiln_ai/adapters/repair/test_repair_task.py +7 -7
  45. kiln_ai/adapters/run_output.py +11 -0
  46. kiln_ai/adapters/test_adapter_registry.py +177 -0
  47. kiln_ai/adapters/test_generate_docs.py +69 -0
  48. kiln_ai/adapters/test_ollama_tools.py +0 -1
  49. kiln_ai/adapters/test_prompt_adaptors.py +25 -18
  50. kiln_ai/adapters/test_prompt_builders.py +265 -44
  51. kiln_ai/adapters/test_provider_tools.py +268 -46
  52. kiln_ai/datamodel/__init__.py +51 -772
  53. kiln_ai/datamodel/basemodel.py +31 -11
  54. kiln_ai/datamodel/datamodel_enums.py +58 -0
  55. kiln_ai/datamodel/dataset_filters.py +114 -0
  56. kiln_ai/datamodel/dataset_split.py +170 -0
  57. kiln_ai/datamodel/eval.py +298 -0
  58. kiln_ai/datamodel/finetune.py +105 -0
  59. kiln_ai/datamodel/json_schema.py +14 -3
  60. kiln_ai/datamodel/model_cache.py +8 -3
  61. kiln_ai/datamodel/project.py +23 -0
  62. kiln_ai/datamodel/prompt.py +37 -0
  63. kiln_ai/datamodel/prompt_id.py +83 -0
  64. kiln_ai/datamodel/strict_mode.py +24 -0
  65. kiln_ai/datamodel/task.py +181 -0
  66. kiln_ai/datamodel/task_output.py +321 -0
  67. kiln_ai/datamodel/task_run.py +164 -0
  68. kiln_ai/datamodel/test_basemodel.py +80 -2
  69. kiln_ai/datamodel/test_dataset_filters.py +71 -0
  70. kiln_ai/datamodel/test_dataset_split.py +127 -6
  71. kiln_ai/datamodel/test_datasource.py +3 -2
  72. kiln_ai/datamodel/test_eval_model.py +635 -0
  73. kiln_ai/datamodel/test_example_models.py +34 -17
  74. kiln_ai/datamodel/test_json_schema.py +23 -0
  75. kiln_ai/datamodel/test_model_cache.py +24 -0
  76. kiln_ai/datamodel/test_model_perf.py +125 -0
  77. kiln_ai/datamodel/test_models.py +131 -2
  78. kiln_ai/datamodel/test_prompt_id.py +129 -0
  79. kiln_ai/datamodel/test_task.py +159 -0
  80. kiln_ai/utils/config.py +6 -1
  81. kiln_ai/utils/exhaustive_error.py +6 -0
  82. {kiln_ai-0.8.1.dist-info → kiln_ai-0.12.0.dist-info}/METADATA +45 -7
  83. kiln_ai-0.12.0.dist-info/RECORD +100 -0
  84. kiln_ai/adapters/base_adapter.py +0 -191
  85. kiln_ai/adapters/langchain_adapters.py +0 -256
  86. kiln_ai-0.8.1.dist-info/RECORD +0 -58
  87. {kiln_ai-0.8.1.dist-info → kiln_ai-0.12.0.dist-info}/WHEEL +0 -0
  88. {kiln_ai-0.8.1.dist-info → kiln_ai-0.12.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,159 @@
1
+ import pytest
2
+ from pydantic import ValidationError
3
+
4
+ from kiln_ai.datamodel.datamodel_enums import TaskOutputRatingType
5
+ from kiln_ai.datamodel.prompt_id import PromptGenerators
6
+ from kiln_ai.datamodel.task import RunConfig, RunConfigProperties, Task, TaskRunConfig
7
+ from kiln_ai.datamodel.task_output import normalize_rating
8
+
9
+
10
+ def test_runconfig_valid_creation():
11
+ task = Task(id="task1", name="Test Task", instruction="Do something")
12
+
13
+ config = RunConfig(
14
+ task=task,
15
+ model_name="gpt-4",
16
+ model_provider_name="openai",
17
+ prompt_id=PromptGenerators.SIMPLE,
18
+ )
19
+
20
+ assert config.task == task
21
+ assert config.model_name == "gpt-4"
22
+ assert config.model_provider_name == "openai"
23
+ assert config.prompt_id == PromptGenerators.SIMPLE # Check default value
24
+
25
+
26
+ def test_runconfig_missing_required_fields():
27
+ with pytest.raises(ValidationError) as exc_info:
28
+ RunConfig()
29
+
30
+ errors = exc_info.value.errors()
31
+ assert (
32
+ len(errors) == 4
33
+ ) # task, model_name, model_provider_name, and prompt_id are required
34
+ assert any(error["loc"][0] == "task" for error in errors)
35
+ assert any(error["loc"][0] == "model_name" for error in errors)
36
+ assert any(error["loc"][0] == "model_provider_name" for error in errors)
37
+ assert any(error["loc"][0] == "prompt_id" for error in errors)
38
+
39
+
40
+ def test_runconfig_custom_prompt_id():
41
+ task = Task(id="task1", name="Test Task", instruction="Do something")
42
+
43
+ config = RunConfig(
44
+ task=task,
45
+ model_name="gpt-4",
46
+ model_provider_name="openai",
47
+ prompt_id=PromptGenerators.SIMPLE_CHAIN_OF_THOUGHT,
48
+ )
49
+
50
+ assert config.prompt_id == PromptGenerators.SIMPLE_CHAIN_OF_THOUGHT
51
+
52
+
53
+ @pytest.fixture
54
+ def sample_task():
55
+ return Task(name="Test Task", instruction="Test instruction")
56
+
57
+
58
+ @pytest.fixture
59
+ def sample_run_config_props(sample_task):
60
+ return RunConfigProperties(
61
+ model_name="gpt-4",
62
+ model_provider_name="openai",
63
+ prompt_id=PromptGenerators.SIMPLE,
64
+ )
65
+
66
+
67
+ def test_task_run_config_valid_creation(sample_task, sample_run_config_props):
68
+ config = TaskRunConfig(
69
+ name="Test Config",
70
+ description="Test description",
71
+ run_config_properties=sample_run_config_props,
72
+ parent=sample_task,
73
+ )
74
+
75
+ assert config.name == "Test Config"
76
+ assert config.description == "Test description"
77
+ assert config.run_config_properties == sample_run_config_props
78
+ assert config.parent_task() == sample_task
79
+
80
+
81
+ def test_task_run_config_minimal_creation(sample_task, sample_run_config_props):
82
+ # Test creation with only required fields
83
+ config = TaskRunConfig(
84
+ name="Test Config",
85
+ run_config_properties=sample_run_config_props,
86
+ parent=sample_task,
87
+ )
88
+
89
+ assert config.name == "Test Config"
90
+ assert config.description is None
91
+ assert config.run_config_properties == sample_run_config_props
92
+
93
+
94
+ def test_task_run_config_missing_required_fields(sample_task):
95
+ # Test missing name
96
+ with pytest.raises(ValidationError) as exc_info:
97
+ TaskRunConfig(
98
+ run_config_properties=RunConfigProperties(
99
+ task=sample_task, model_name="gpt-4", model_provider_name="openai"
100
+ ),
101
+ parent=sample_task,
102
+ )
103
+ assert "Field required" in str(exc_info.value)
104
+
105
+ # Test missing run_config
106
+ with pytest.raises(ValidationError) as exc_info:
107
+ TaskRunConfig(name="Test Config", parent=sample_task)
108
+ assert "Field required" in str(exc_info.value)
109
+
110
+
111
+ def test_task_run_config_missing_task_in_run_config(sample_task):
112
+ with pytest.raises(
113
+ ValidationError, match="Input should be a valid dictionary or instance of Task"
114
+ ):
115
+ # Create a run config without a task
116
+ RunConfig(
117
+ model_name="gpt-4",
118
+ model_provider_name="openai",
119
+ task=None, # type: ignore
120
+ )
121
+
122
+
123
+ @pytest.mark.parametrize(
124
+ "rating_type,rating,expected",
125
+ [
126
+ (TaskOutputRatingType.five_star, 1, 0),
127
+ (TaskOutputRatingType.five_star, 2, 0.25),
128
+ (TaskOutputRatingType.five_star, 3, 0.5),
129
+ (TaskOutputRatingType.five_star, 4, 0.75),
130
+ (TaskOutputRatingType.five_star, 5, 1),
131
+ (TaskOutputRatingType.pass_fail, 0, 0),
132
+ (TaskOutputRatingType.pass_fail, 1, 1),
133
+ (TaskOutputRatingType.pass_fail, 0.5, 0.5),
134
+ (TaskOutputRatingType.pass_fail_critical, -1, 0),
135
+ (TaskOutputRatingType.pass_fail_critical, 0, 0.5),
136
+ (TaskOutputRatingType.pass_fail_critical, 1, 1),
137
+ (TaskOutputRatingType.pass_fail_critical, 0.5, 0.75),
138
+ ],
139
+ )
140
+ def test_normalize_rating(rating_type, rating, expected):
141
+ assert normalize_rating(rating, rating_type) == expected
142
+
143
+
144
+ @pytest.mark.parametrize(
145
+ "rating_type,rating",
146
+ [
147
+ (TaskOutputRatingType.five_star, 0),
148
+ (TaskOutputRatingType.five_star, 6),
149
+ (TaskOutputRatingType.pass_fail, -0.5),
150
+ (TaskOutputRatingType.pass_fail, 1.5),
151
+ (TaskOutputRatingType.pass_fail_critical, -1.5),
152
+ (TaskOutputRatingType.pass_fail_critical, 1.5),
153
+ (TaskOutputRatingType.custom, 0),
154
+ (TaskOutputRatingType.custom, 99),
155
+ ],
156
+ )
157
+ def test_normalize_rating_errors(rating_type, rating):
158
+ with pytest.raises(ValueError):
159
+ normalize_rating(rating, rating_type)
kiln_ai/utils/config.py CHANGED
@@ -142,10 +142,15 @@ class Config:
142
142
  raise AttributeError(f"Config has no attribute '{name}'")
143
143
 
144
144
  @classmethod
145
- def settings_path(cls, create=True):
145
+ def settings_dir(cls, create=True):
146
146
  settings_dir = os.path.join(Path.home(), ".kiln_ai")
147
147
  if create and not os.path.exists(settings_dir):
148
148
  os.makedirs(settings_dir)
149
+ return settings_dir
150
+
151
+ @classmethod
152
+ def settings_path(cls, create=True):
153
+ settings_dir = cls.settings_dir(create)
149
154
  return os.path.join(settings_dir, "settings.yaml")
150
155
 
151
156
  @classmethod
@@ -0,0 +1,6 @@
1
+ from typing import NoReturn
2
+
3
+
4
+ # Weird trick, but passing a enum to NoReturn triggers the type checker to complain unless all values are handled.
5
+ def raise_exhaustive_enum_error(value: NoReturn) -> NoReturn:
6
+ raise ValueError(f"Unhandled enum value: {value}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kiln-ai
3
- Version: 0.8.1
3
+ Version: 0.12.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,8 +19,7 @@ Requires-Dist: jsonschema>=4.23.0
19
19
  Requires-Dist: langchain-aws>=0.2.4
20
20
  Requires-Dist: langchain-fireworks>=0.2.5
21
21
  Requires-Dist: langchain-groq>=0.2.0
22
- Requires-Dist: langchain-ollama>=0.2.0
23
- Requires-Dist: langchain-openai>=0.2.4
22
+ Requires-Dist: langchain-ollama>=0.2.2
24
23
  Requires-Dist: langchain>=0.3.5
25
24
  Requires-Dist: openai>=1.53.0
26
25
  Requires-Dist: pdoc>=15.0.0
@@ -72,7 +71,8 @@ The library has a [comprehensive set of docs](https://kiln-ai.github.io/Kiln/kil
72
71
  - [Load an Existing Dataset into a Kiln Task Dataset](#load-an-existing-dataset-into-a-kiln-task-dataset)
73
72
  - [Using your Kiln Dataset in a Notebook or Project](#using-your-kiln-dataset-in-a-notebook-or-project)
74
73
  - [Using Kiln Dataset in Pandas](#using-kiln-dataset-in-pandas)
75
- - [Advanced Usage](#advanced-usage)
74
+ - [Building and Running a Kiln Task from Code](#building-and-running-a-kiln-task-from-code)
75
+ - [Full API Reference](#full-api-reference)
76
76
 
77
77
  ## Installation
78
78
 
@@ -95,11 +95,14 @@ The Kiln Python library provides a set of Python classes that which help you eas
95
95
 
96
96
  ### Datamodel Overview
97
97
 
98
+ Here's a high level overview of the Kiln datamodel. A project folder will reflect this nested structure:
99
+
98
100
  - Project: a Kiln Project that organizes related tasks
99
101
  - Task: a specific task including prompt instructions, input/output schemas, and requirements
100
102
  - TaskRun: a sample (run) of a task including input, output and human rating information
101
- - DatasetSplit: a frozen collection of task runs divided into train/test/validation splits
102
103
  - Finetune: configuration and status tracking for fine-tuning models on task data
104
+ - Prompt: a prompt for this task
105
+ - DatasetSplit: a frozen collection of task runs divided into train/test/validation splits
103
106
 
104
107
  ### Load a Project
105
108
 
@@ -230,8 +233,43 @@ final_df = pd.concat(dfs, ignore_index=True)
230
233
  print(final_df)
231
234
  ```
232
235
 
233
- ### Advanced Usage
236
+ ### Building and Running a Kiln Task from Code
237
+
238
+ ```python
239
+ # Step 1: Create or Load a Task -- choose one of the following 1.A or 1.B
240
+
241
+ # Step 1.A: Optionally load an existing task from disk
242
+ # task = datamodel.Task.load_from_file("path/to/task.kiln")
243
+
244
+ # Step 1.B: Create a new task in code, without saving to disk.
245
+ task = datamodel.Task(
246
+ name="test task",
247
+ instruction="Tell a joke, given a subject.",
248
+ )
249
+ # replace with a valid JSON schema https://json-schema.org for your task (json string, not a python dict).
250
+ # Or delete this line to use plaintext output
251
+ task.output_json_schema = json_joke_schema
252
+
253
+ # Step 2: Create an Adapter to run the task, with a specific model and provider
254
+ adapter = adapter_for_task(task, model_name="llama_3_1_8b", provider="groq")
255
+
256
+ # Step 3: Invoke the Adapter to run the task
257
+ task_input = "cows"
258
+ response = await adapter.invoke(task_input)
259
+ print(f"Output: {response.output.output}")
260
+
261
+ # Step 4 (optional): Load the task from disk and print the results.
262
+ # This will only work if the task was loaded from disk, or you called task.save_to_file() before invoking the adapter (epemerial tasks don't save their result to disk)
263
+ task = datamodel.Task.load_from_file(tmp_path / "test_task.kiln")
264
+ for run in task.runs():
265
+ print(f"Run: {run.id}")
266
+ print(f"Input: {run.input}")
267
+ print(f"Output: {run.output}")
268
+
269
+ ```
270
+
271
+ ## Full API Reference
234
272
 
235
273
  The library can do a lot more than the examples we've shown here.
236
274
 
237
- See the [docs](https://kiln-ai.github.io/Kiln/kiln_core_docs/index.html) for more information.
275
+ See the full API reference in the [docs](https://kiln-ai.github.io/Kiln/kiln_core_docs/index.html) under the `Submodules` section of the sidebar.
@@ -0,0 +1,100 @@
1
+ kiln_ai/__init__.py,sha256=Sc4z8LRVFMwJUoc_DPVUriSXTZ6PO9MaJ80PhRbKyB8,34
2
+ kiln_ai/adapters/__init__.py,sha256=4qEnFkkRSHPKDU7AvYNkqXECjZO_K7PzDCK3HbsY7o4,902
3
+ kiln_ai/adapters/adapter_registry.py,sha256=o7JhzL627W3WMvpztsI_D0pqLPXP-IgIf3e-o7DAVxE,3720
4
+ kiln_ai/adapters/ml_model_list.py,sha256=IzxswO2zORd7bsovswvRpZMwIs1BZcMtPcnhLZ7xzkk,40969
5
+ kiln_ai/adapters/ollama_tools.py,sha256=ZkiGCaocKTMsb1JoySupv9a1OQuE72CCuKsNpyp6jNU,3551
6
+ kiln_ai/adapters/prompt_builders.py,sha256=LYHTIaisQMBFtWDRIGo1QJgOsmQ-NBpQ8fI4eImHxaQ,15269
7
+ kiln_ai/adapters/provider_tools.py,sha256=CGNLW0xhFyj93HFwznCoDrrbyQbQAaS2mJuOKaMB6gU,14435
8
+ kiln_ai/adapters/run_output.py,sha256=_WVNqJ9cQehgEJR3Jy5_Pp29QnurpmEf-S6UU6WAegE,271
9
+ kiln_ai/adapters/test_adapter_registry.py,sha256=opowxLBWm0lZTPL9S4qEaOS8HB82dTpZeNuhpE_cNHU,6379
10
+ kiln_ai/adapters/test_generate_docs.py,sha256=RQ5flkg4fbosj_fB3RiRZyXSqD_UtOHNBYJsne6UkzU,2782
11
+ kiln_ai/adapters/test_ollama_tools.py,sha256=xAUzL0IVmmXadVehJu1WjqbhpKEYGAgGt3pWx7hrubc,2514
12
+ kiln_ai/adapters/test_prompt_adaptors.py,sha256=CKyToDKS4v-tQO9pq4tiq_ypnY4ePhY9yrRAtG-58p0,7516
13
+ kiln_ai/adapters/test_prompt_builders.py,sha256=5Xvfr-oQg_LLrle6UqfpRHWcPUYa8ywG3aL1rM7q1Jw,22054
14
+ kiln_ai/adapters/test_provider_tools.py,sha256=DtnC6oFuiBvvbhD-kdCcWzEYqXZfMBM_DexuQdyAVR8,28664
15
+ kiln_ai/adapters/data_gen/__init__.py,sha256=QTZWaf7kq5BorhPvexJfwDEKmjRmIbhwW9ei8LW2SIs,276
16
+ kiln_ai/adapters/data_gen/data_gen_prompts.py,sha256=kudjHnAz7L3q0k_NLyTlaIV7M0uRFrxXNcfcnjOE2uc,5810
17
+ kiln_ai/adapters/data_gen/data_gen_task.py,sha256=0PuYCcj09BtpgNj23mKj_L45mKZBdV5VreUeZ-Tj_xM,6642
18
+ kiln_ai/adapters/data_gen/test_data_gen_task.py,sha256=cRKUKMvC0uVompbmPTKwbnQ_N3c0cQDm4J_9H4Y5U18,10129
19
+ kiln_ai/adapters/eval/base_eval.py,sha256=jVXMiVBC07ZnLEuZVAjUAYewsnuV99put39n_GZcG1M,7261
20
+ kiln_ai/adapters/eval/eval_runner.py,sha256=A8GhVEt4J_p2-EZlN592blVxY0anKiMiLgac155pcfQ,10688
21
+ kiln_ai/adapters/eval/g_eval.py,sha256=VXYZi-5WG8Go4E2shaOL4D3V2cL_c2zmEno2N1b2WPM,14295
22
+ kiln_ai/adapters/eval/registry.py,sha256=gZ_s0VgEx79Fswkgi1tS4yOl7lzpkvUBJZ62RldhM_w,626
23
+ kiln_ai/adapters/eval/test_base_eval.py,sha256=AGq09bziZm9zh_37PP59AzpkWW7hQU1o7vHSiDsObhY,10723
24
+ kiln_ai/adapters/eval/test_eval_runner.py,sha256=58jRE_2qHZmsDlMj41DrbgE8w9PKC9wwAT-vbi_R4Ec,18567
25
+ kiln_ai/adapters/eval/test_g_eval.py,sha256=wcR56b3vSKn88JeCCQz92p8TMgZlgSP1ged_XlFrYlg,16162
26
+ kiln_ai/adapters/eval/test_g_eval_data.py,sha256=8caiZfLWnXVX8alrBPrH7L7gqqSS9vO7u6PzcHurQcA,27769
27
+ kiln_ai/adapters/fine_tune/__init__.py,sha256=DxdTR60chwgck1aEoVYWyfWi6Ed2ZkdJj0lar-SEAj4,257
28
+ kiln_ai/adapters/fine_tune/base_finetune.py,sha256=n3mfE_3bhhzmN_MQxO5qNezN-qpl4WFamZ3ih41dx4o,6069
29
+ kiln_ai/adapters/fine_tune/dataset_formatter.py,sha256=qRhSSkMhTWn13OMb6LKPVwAU7uY4bB49GDiVSuhDkNg,14449
30
+ kiln_ai/adapters/fine_tune/finetune_registry.py,sha256=H1B-opCTlIyd9JlIFTKsY_ctxUX9ziEc49_gnmg1SZg,483
31
+ kiln_ai/adapters/fine_tune/fireworks_finetune.py,sha256=6IfTDn_8tg6PR0OFudRx6V7Wjvf4P7t0fm_xyRwII68,13978
32
+ kiln_ai/adapters/fine_tune/openai_finetune.py,sha256=Dz9E_0BWfrIkvv8ArZe-RKPwbIKPZ3v8rfbc3JELyTY,8571
33
+ kiln_ai/adapters/fine_tune/test_base_finetune.py,sha256=0zWxFYrDGVuoQNQmi9vVUEkBc4mstfHnsUjQmiJA-sE,10864
34
+ kiln_ai/adapters/fine_tune/test_dataset_formatter.py,sha256=T3jbFZooLVBaGCE0LUVxwPxzM3l8IY41zUj3jPk-Zi8,24027
35
+ kiln_ai/adapters/fine_tune/test_fireworks_tinetune.py,sha256=e88z5-KtU9Y7frXqCVy6r6iE6S-tInn5oMOqmSnbR2I,18144
36
+ kiln_ai/adapters/fine_tune/test_openai_finetune.py,sha256=H63Xk2PNHbt5Ev5IQpdR9JZ4uz-Huo2gfuC4mHHqe0w,20011
37
+ kiln_ai/adapters/model_adapters/__init__.py,sha256=FyNq-twr1zQR55Hd_sDlTcVZ8JsZ9jrIBBURtZNjlss,272
38
+ kiln_ai/adapters/model_adapters/base_adapter.py,sha256=tY67FJlWzYY-Ha1FyBMes3KacklFfTSqvU6-crILQsc,9597
39
+ kiln_ai/adapters/model_adapters/langchain_adapters.py,sha256=LVggQGeg_fIol1uYo375JHmjh7pwDhCACVe1K7lh28Y,12996
40
+ kiln_ai/adapters/model_adapters/openai_compatible_config.py,sha256=oxiUUESM9f5EVMePDSJI7s6YaMmmBkFMCEdxA50mwgw,241
41
+ kiln_ai/adapters/model_adapters/openai_model_adapter.py,sha256=KuCPFuNZ5aZwymLL8k87PNjUVOs9JyR91W7VKtw9yN8,11438
42
+ kiln_ai/adapters/model_adapters/test_base_adapter.py,sha256=uQyKrHLN3Jha6R-6SWkEME6brQecVFdPTSXogo-xpt0,6556
43
+ kiln_ai/adapters/model_adapters/test_langchain_adapter.py,sha256=PArWTKytzUoM9Lc9Q0bEOcvZDNTF2SzfR9ln8sf0Hzg,11884
44
+ kiln_ai/adapters/model_adapters/test_openai_model_adapter.py,sha256=CV6a3Sf3f3szpk1MLBoAjcuL5B5-4n86j8tMlEA-Bhg,6844
45
+ kiln_ai/adapters/model_adapters/test_saving_adapter_results.py,sha256=1XFQQxdSIbqSoQEdxHOYJcY0cMb59qpTDPOmL9bW4B8,7870
46
+ kiln_ai/adapters/model_adapters/test_structured_output.py,sha256=7N5xniBWXDxwb4gvV8k0bbrlTir2kWBE6Q_z2azBJvs,11865
47
+ kiln_ai/adapters/parsers/__init__.py,sha256=TGJS_8JhjUwg5Bnq4cDmwt5eIRo4vowmcL2A72L1Hzk,202
48
+ kiln_ai/adapters/parsers/base_parser.py,sha256=DaoZVEOOuFTMZd5ZTpl_as6-xc9NPWGP2fAmP12J58M,389
49
+ kiln_ai/adapters/parsers/json_parser.py,sha256=IszrBrhIFrrVr76UZsuejkBdqpZG27mU72264HVgVzE,1274
50
+ kiln_ai/adapters/parsers/parser_registry.py,sha256=G9bAZrnWrR0a82JAQHsSqA2o7-CjrZUBANZljY_6ZxE,623
51
+ kiln_ai/adapters/parsers/r1_parser.py,sha256=9nMEWDAbRSTFuu_--0HMVfVg9IYSoUNQHHw9OxETlRw,2558
52
+ kiln_ai/adapters/parsers/test_json_parser.py,sha256=9kdWe_vRC5wjP8A1Ym6Zu6enDIz4ARCNiRpcZr7_3ak,1971
53
+ kiln_ai/adapters/parsers/test_parser_registry.py,sha256=S4MdX7cnhCbmeKq8tZwMwRdGWr-019Z-fw5zey9Wm08,1043
54
+ kiln_ai/adapters/parsers/test_r1_parser.py,sha256=Ys1ICRNVgt54rf8IEKNav5sz9zHYvvcVAUuoSwwftg8,4517
55
+ kiln_ai/adapters/repair/__init__.py,sha256=dOO9MEpEhjiwzDVFg3MNfA2bKMPlax9iekDatpTkX8E,217
56
+ kiln_ai/adapters/repair/repair_task.py,sha256=iW0bHWQq6Tir6ULTATWFS0zpwNji8Tbwhm2lZu52RsM,3342
57
+ kiln_ai/adapters/repair/test_repair_task.py,sha256=iY7h-o-hnB0zwlkX--WuQlCsd5sKbhksS0hIIPCxt7E,7944
58
+ kiln_ai/datamodel/__init__.py,sha256=GbRfDrdSq9d_-HxzmFIicTmLO3qz-O3XGvSwDPh3XCk,1957
59
+ kiln_ai/datamodel/basemodel.py,sha256=TwMBfNFJ7-5bp2QOoTQUl_YVrF0pkDAk5Rdk6EWEXxI,22143
60
+ kiln_ai/datamodel/datamodel_enums.py,sha256=w8aJeuLWdrH6ZCZ0y2-o0IOmXcl7qXpOMHyrHHoJmkA,2040
61
+ kiln_ai/datamodel/dataset_filters.py,sha256=hWKxGJ-mSl4y0igyNcpmRoRYCiGrf0_uN4MMU9Fe_ng,3180
62
+ kiln_ai/datamodel/dataset_split.py,sha256=q4l4SlUvjLV547bzk7Z-fbmj_o26GDcYOZ2rA5RPh3c,5612
63
+ kiln_ai/datamodel/eval.py,sha256=kio2LqQ87MsP75DJTiIVdVfopTZXH4xjGN9g11V1mUU,13826
64
+ kiln_ai/datamodel/finetune.py,sha256=TYoNVRAfbjqvrY-1YmHwG6xSoDljiJWuuVcTbvQAJL4,4569
65
+ kiln_ai/datamodel/json_schema.py,sha256=sjc2LkbWWFhlqX5QOvLeWrovkmoX_tn3iQquxKDA8Pk,2990
66
+ kiln_ai/datamodel/model_cache.py,sha256=9X4aAigbkFdytckgw8InCMh86uBna0ME_1HJSeMPEn0,4495
67
+ kiln_ai/datamodel/project.py,sha256=uVH2_3TDFtsG_tpts81A-zbd9uPDFxAwMCKZt_km3IE,727
68
+ kiln_ai/datamodel/prompt.py,sha256=70JPYHfgyX18cHW_DXoMzIOA28Jbaz6gyabElmpycyc,1161
69
+ kiln_ai/datamodel/prompt_id.py,sha256=eU2TV0RZapn-BgnZ4sOSNOOVEQ3aPaLzW4YSYCd3OBo,2531
70
+ kiln_ai/datamodel/registry.py,sha256=XwGFXJFKZtOpR1Z9ven6SftggfADdZRm8TFxCEVtfUQ,957
71
+ kiln_ai/datamodel/strict_mode.py,sha256=sm4Xka8mnJHCShtbh6MMU5dDQv-cLj8lHgHkmFKpsl0,849
72
+ kiln_ai/datamodel/task.py,sha256=r-_zgrQCIiIkN8gvBISdU449Z9oKp7E1XL0lkik_rVI,7036
73
+ kiln_ai/datamodel/task_output.py,sha256=0h4QvzV-hksE_AGHWsUHbYf5F95Zn7uU7WFbeIbAEck,12507
74
+ kiln_ai/datamodel/task_run.py,sha256=yquE0jyr_9WzcvrMsEmZfXUnn8zZDEZIXZhVcVBMrT8,7038
75
+ kiln_ai/datamodel/test_basemodel.py,sha256=KJLJf0stuQq4ksOtoPM_w1VQrGz2FGdOT6cdrMkib9s,17750
76
+ kiln_ai/datamodel/test_dataset_filters.py,sha256=v88QPkIsq4diUmoUF3-qj5KAW2rLRp0KDAm_pexbFy4,1894
77
+ kiln_ai/datamodel/test_dataset_split.py,sha256=5CHO1Lq4xQBB72tV2SPER7OZODJNvj15qxi_cYBV2Rs,11157
78
+ kiln_ai/datamodel/test_datasource.py,sha256=Pzh1l20__xObgdBaIMNJarG-jwmEsujRFkRmUBLuK0g,3220
79
+ kiln_ai/datamodel/test_eval_model.py,sha256=J7MqwWBgPpeXGqh3IacVUUHdZFJSZ2MgTsUNu-hNOJw,19528
80
+ kiln_ai/datamodel/test_example_models.py,sha256=fpqh0u7zFhWHcRHgtxCjX8RD2oKHYOP_mJJymaUhEZU,20944
81
+ kiln_ai/datamodel/test_json_schema.py,sha256=UgKwAFcdrJTq2byh7Yf-HoSAtiHiGAsNZxfkIvoMxIg,3915
82
+ kiln_ai/datamodel/test_model_cache.py,sha256=Fy-ucYNzS5JEG-8SFY4nVHA8iRbXXxai20f8_oGl97o,8184
83
+ kiln_ai/datamodel/test_model_perf.py,sha256=NdD7L8XraGkunaEKGPsfYwdcbIgdjhFanOO3G6hU158,3235
84
+ kiln_ai/datamodel/test_models.py,sha256=hmV7sTbOamWJCwOY96w-g4PQRv4Uai-XaHtg0QKH-ak,19295
85
+ kiln_ai/datamodel/test_nested_save.py,sha256=xciCddqvPyKyoyjC5Lx_3Kh1t4LJv1xYRAPazR3SRcs,5588
86
+ kiln_ai/datamodel/test_output_rating.py,sha256=zvPIp2shAgCs2RQBgwYoL09fRA3krHvgAqUa91RlWR0,15125
87
+ kiln_ai/datamodel/test_prompt_id.py,sha256=ihyXVPQi0dSLGnBM7rTXRnVaiWXhh7HJmSy4nZZKmso,4225
88
+ kiln_ai/datamodel/test_registry.py,sha256=PhS4anLi5Bf_023obuTlO5DALhtPB8WIc_bX12Yg6Po,2705
89
+ kiln_ai/datamodel/test_task.py,sha256=FYyoEqJXQIy8rcBsLTdki4-1z9COnZQk1-aoS3ZoNuU,5307
90
+ kiln_ai/utils/__init__.py,sha256=PTD0MwBCKAMIOGsTAwsFaJOusTJJoRFTfOGqRvCaU-E,142
91
+ kiln_ai/utils/config.py,sha256=9navMS2ooSviz74Bq8raf5-01DFfDf9SSVfpasIIPlo,6993
92
+ kiln_ai/utils/exhaustive_error.py,sha256=TkkRixIAR3CPEKHeAJzyv0mtxp6BxUBKMvobA3vzQug,262
93
+ kiln_ai/utils/formatting.py,sha256=VtB9oag0lOGv17dwT7OPX_3HzBfaU9GsLH-iLete0yM,97
94
+ kiln_ai/utils/name_generator.py,sha256=v26TgpCwQbhQFcZvzgjZvURinjrOyyFhxpsI6NQrHKc,1914
95
+ kiln_ai/utils/test_config.py,sha256=Jw3nMFeIgZUsZDRJJY2HpB-2EkR2NoZ-rDe_o9oA7ws,9174
96
+ kiln_ai/utils/test_name_geneator.py,sha256=9-hSTBshyakqlPbFnNcggwLrL7lcPTitauBYHg9jFWI,1513
97
+ kiln_ai-0.12.0.dist-info/METADATA,sha256=CnOHwkyknO0XqFIRL65XVEQl_375cHnvMneIy8J3PWE,10656
98
+ kiln_ai-0.12.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
99
+ kiln_ai-0.12.0.dist-info/licenses/LICENSE.txt,sha256=_NA5pnTYgRRr4qH6lE3X-TuZJ8iRcMUi5ASoGr-lEx8,1209
100
+ kiln_ai-0.12.0.dist-info/RECORD,,
@@ -1,191 +0,0 @@
1
- import json
2
- from abc import ABCMeta, abstractmethod
3
- from dataclasses import dataclass
4
- from typing import Dict
5
-
6
- from kiln_ai.datamodel import (
7
- DataSource,
8
- DataSourceType,
9
- Task,
10
- TaskOutput,
11
- TaskRun,
12
- )
13
- from kiln_ai.datamodel.json_schema import validate_schema
14
- from kiln_ai.utils.config import Config
15
-
16
- from .prompt_builders import BasePromptBuilder, SimplePromptBuilder
17
-
18
-
19
- @dataclass
20
- class AdapterInfo:
21
- adapter_name: str
22
- model_name: str
23
- model_provider: str
24
- prompt_builder_name: str
25
-
26
-
27
- @dataclass
28
- class RunOutput:
29
- output: Dict | str
30
- intermediate_outputs: Dict[str, str] | None
31
-
32
-
33
- class BaseAdapter(metaclass=ABCMeta):
34
- """Base class for AI model adapters that handle task execution.
35
-
36
- This abstract class provides the foundation for implementing model-specific adapters
37
- that can process tasks with structured or unstructured inputs/outputs. It handles
38
- input/output validation, prompt building, and run tracking.
39
-
40
- Attributes:
41
- prompt_builder (BasePromptBuilder): Builder for constructing prompts for the model
42
- kiln_task (Task): The task configuration and metadata
43
- output_schema (dict | None): JSON schema for validating structured outputs
44
- input_schema (dict | None): JSON schema for validating structured inputs
45
- """
46
-
47
- def __init__(
48
- self,
49
- kiln_task: Task,
50
- prompt_builder: BasePromptBuilder | None = None,
51
- tags: list[str] | None = None,
52
- ):
53
- self.prompt_builder = prompt_builder or SimplePromptBuilder(kiln_task)
54
- self.kiln_task = kiln_task
55
- self.output_schema = self.kiln_task.output_json_schema
56
- self.input_schema = self.kiln_task.input_json_schema
57
- self.default_tags = tags
58
-
59
- async def invoke_returning_raw(
60
- self,
61
- input: Dict | str,
62
- input_source: DataSource | None = None,
63
- ) -> Dict | str:
64
- result = await self.invoke(input, input_source)
65
- if self.kiln_task.output_json_schema is None:
66
- return result.output.output
67
- else:
68
- return json.loads(result.output.output)
69
-
70
- async def invoke(
71
- self,
72
- input: Dict | str,
73
- input_source: DataSource | None = None,
74
- ) -> TaskRun:
75
- # validate input
76
- if self.input_schema is not None:
77
- if not isinstance(input, dict):
78
- raise ValueError(f"structured input is not a dict: {input}")
79
- validate_schema(input, self.input_schema)
80
-
81
- # Run
82
- run_output = await self._run(input)
83
-
84
- # validate output
85
- if self.output_schema is not None:
86
- if not isinstance(run_output.output, dict):
87
- raise RuntimeError(
88
- f"structured response is not a dict: {run_output.output}"
89
- )
90
- validate_schema(run_output.output, self.output_schema)
91
- else:
92
- if not isinstance(run_output.output, str):
93
- raise RuntimeError(
94
- f"response is not a string for non-structured task: {run_output.output}"
95
- )
96
-
97
- # Generate the run and output
98
- run = self.generate_run(input, input_source, run_output)
99
-
100
- # Save the run if configured to do so, and we have a path to save to
101
- if Config.shared().autosave_runs and self.kiln_task.path is not None:
102
- run.save_to_file()
103
- else:
104
- # Clear the ID to indicate it's not persisted
105
- run.id = None
106
-
107
- return run
108
-
109
- def has_structured_output(self) -> bool:
110
- return self.output_schema is not None
111
-
112
- @abstractmethod
113
- def adapter_info(self) -> AdapterInfo:
114
- pass
115
-
116
- @abstractmethod
117
- async def _run(self, input: Dict | str) -> RunOutput:
118
- pass
119
-
120
- def build_prompt(self) -> str:
121
- return self.prompt_builder.build_prompt()
122
-
123
- # create a run and task output
124
- def generate_run(
125
- self, input: Dict | str, input_source: DataSource | None, run_output: RunOutput
126
- ) -> TaskRun:
127
- # Convert input and output to JSON strings if they are dictionaries
128
- input_str = json.dumps(input) if isinstance(input, dict) else input
129
- output_str = (
130
- json.dumps(run_output.output)
131
- if isinstance(run_output.output, dict)
132
- else run_output.output
133
- )
134
-
135
- # If no input source is provided, use the human data source
136
- if input_source is None:
137
- input_source = DataSource(
138
- type=DataSourceType.human,
139
- properties={"created_by": Config.shared().user_id},
140
- )
141
-
142
- new_task_run = TaskRun(
143
- parent=self.kiln_task,
144
- input=input_str,
145
- input_source=input_source,
146
- output=TaskOutput(
147
- output=output_str,
148
- # Synthetic since an adapter, not a human, is creating this
149
- source=DataSource(
150
- type=DataSourceType.synthetic,
151
- properties=self._properties_for_task_output(),
152
- ),
153
- ),
154
- intermediate_outputs=run_output.intermediate_outputs,
155
- tags=self.default_tags or [],
156
- )
157
-
158
- exclude_fields = {
159
- "id": True,
160
- "created_at": True,
161
- "updated_at": True,
162
- "path": True,
163
- "output": {"id": True, "created_at": True, "updated_at": True},
164
- }
165
- new_run_dump = new_task_run.model_dump(exclude=exclude_fields)
166
-
167
- # Check if the same run already exists
168
- existing_task_run = next(
169
- (
170
- task_run
171
- for task_run in self.kiln_task.runs()
172
- if task_run.model_dump(exclude=exclude_fields) == new_run_dump
173
- ),
174
- None,
175
- )
176
- if existing_task_run:
177
- return existing_task_run
178
-
179
- return new_task_run
180
-
181
- def _properties_for_task_output(self) -> Dict[str, str | int | float]:
182
- props = {}
183
-
184
- # adapter info
185
- adapter_info = self.adapter_info()
186
- props["adapter_name"] = adapter_info.adapter_name
187
- props["model_name"] = adapter_info.model_name
188
- props["model_provider"] = adapter_info.model_provider
189
- props["prompt_builder_name"] = adapter_info.prompt_builder_name
190
-
191
- return props