kiln-ai 0.18.0__py3-none-any.whl → 0.20.1__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 (89) hide show
  1. kiln_ai/adapters/__init__.py +2 -2
  2. kiln_ai/adapters/adapter_registry.py +46 -0
  3. kiln_ai/adapters/chat/chat_formatter.py +8 -12
  4. kiln_ai/adapters/chat/test_chat_formatter.py +6 -2
  5. kiln_ai/adapters/data_gen/data_gen_task.py +2 -2
  6. kiln_ai/adapters/data_gen/test_data_gen_task.py +7 -3
  7. kiln_ai/adapters/docker_model_runner_tools.py +119 -0
  8. kiln_ai/adapters/eval/base_eval.py +2 -2
  9. kiln_ai/adapters/eval/eval_runner.py +3 -1
  10. kiln_ai/adapters/eval/g_eval.py +2 -2
  11. kiln_ai/adapters/eval/test_base_eval.py +1 -1
  12. kiln_ai/adapters/eval/test_eval_runner.py +6 -12
  13. kiln_ai/adapters/eval/test_g_eval.py +3 -4
  14. kiln_ai/adapters/eval/test_g_eval_data.py +1 -1
  15. kiln_ai/adapters/fine_tune/__init__.py +1 -1
  16. kiln_ai/adapters/fine_tune/base_finetune.py +1 -0
  17. kiln_ai/adapters/fine_tune/fireworks_finetune.py +32 -20
  18. kiln_ai/adapters/fine_tune/openai_finetune.py +14 -4
  19. kiln_ai/adapters/fine_tune/test_fireworks_tinetune.py +30 -21
  20. kiln_ai/adapters/fine_tune/test_openai_finetune.py +108 -111
  21. kiln_ai/adapters/ml_model_list.py +1009 -111
  22. kiln_ai/adapters/model_adapters/base_adapter.py +62 -28
  23. kiln_ai/adapters/model_adapters/litellm_adapter.py +397 -80
  24. kiln_ai/adapters/model_adapters/test_base_adapter.py +194 -18
  25. kiln_ai/adapters/model_adapters/test_litellm_adapter.py +428 -4
  26. kiln_ai/adapters/model_adapters/test_litellm_adapter_tools.py +1103 -0
  27. kiln_ai/adapters/model_adapters/test_saving_adapter_results.py +5 -5
  28. kiln_ai/adapters/model_adapters/test_structured_output.py +120 -14
  29. kiln_ai/adapters/parsers/__init__.py +1 -1
  30. kiln_ai/adapters/parsers/test_r1_parser.py +1 -1
  31. kiln_ai/adapters/provider_tools.py +35 -20
  32. kiln_ai/adapters/remote_config.py +57 -10
  33. kiln_ai/adapters/repair/repair_task.py +1 -1
  34. kiln_ai/adapters/repair/test_repair_task.py +12 -9
  35. kiln_ai/adapters/run_output.py +3 -0
  36. kiln_ai/adapters/test_adapter_registry.py +109 -2
  37. kiln_ai/adapters/test_docker_model_runner_tools.py +305 -0
  38. kiln_ai/adapters/test_ml_model_list.py +51 -1
  39. kiln_ai/adapters/test_prompt_adaptors.py +13 -6
  40. kiln_ai/adapters/test_provider_tools.py +73 -12
  41. kiln_ai/adapters/test_remote_config.py +470 -16
  42. kiln_ai/datamodel/__init__.py +23 -21
  43. kiln_ai/datamodel/basemodel.py +54 -28
  44. kiln_ai/datamodel/datamodel_enums.py +3 -0
  45. kiln_ai/datamodel/dataset_split.py +5 -3
  46. kiln_ai/datamodel/eval.py +4 -4
  47. kiln_ai/datamodel/external_tool_server.py +298 -0
  48. kiln_ai/datamodel/finetune.py +2 -2
  49. kiln_ai/datamodel/json_schema.py +25 -10
  50. kiln_ai/datamodel/project.py +11 -4
  51. kiln_ai/datamodel/prompt.py +2 -2
  52. kiln_ai/datamodel/prompt_id.py +4 -4
  53. kiln_ai/datamodel/registry.py +0 -15
  54. kiln_ai/datamodel/run_config.py +62 -0
  55. kiln_ai/datamodel/task.py +8 -83
  56. kiln_ai/datamodel/task_output.py +7 -2
  57. kiln_ai/datamodel/task_run.py +41 -0
  58. kiln_ai/datamodel/test_basemodel.py +213 -21
  59. kiln_ai/datamodel/test_eval_model.py +6 -6
  60. kiln_ai/datamodel/test_example_models.py +175 -0
  61. kiln_ai/datamodel/test_external_tool_server.py +691 -0
  62. kiln_ai/datamodel/test_model_perf.py +1 -1
  63. kiln_ai/datamodel/test_prompt_id.py +5 -1
  64. kiln_ai/datamodel/test_registry.py +8 -3
  65. kiln_ai/datamodel/test_task.py +20 -47
  66. kiln_ai/datamodel/test_tool_id.py +239 -0
  67. kiln_ai/datamodel/tool_id.py +83 -0
  68. kiln_ai/tools/__init__.py +8 -0
  69. kiln_ai/tools/base_tool.py +82 -0
  70. kiln_ai/tools/built_in_tools/__init__.py +13 -0
  71. kiln_ai/tools/built_in_tools/math_tools.py +124 -0
  72. kiln_ai/tools/built_in_tools/test_math_tools.py +204 -0
  73. kiln_ai/tools/mcp_server_tool.py +95 -0
  74. kiln_ai/tools/mcp_session_manager.py +243 -0
  75. kiln_ai/tools/test_base_tools.py +199 -0
  76. kiln_ai/tools/test_mcp_server_tool.py +457 -0
  77. kiln_ai/tools/test_mcp_session_manager.py +1585 -0
  78. kiln_ai/tools/test_tool_registry.py +473 -0
  79. kiln_ai/tools/tool_registry.py +64 -0
  80. kiln_ai/utils/config.py +32 -0
  81. kiln_ai/utils/open_ai_types.py +94 -0
  82. kiln_ai/utils/project_utils.py +17 -0
  83. kiln_ai/utils/test_config.py +138 -1
  84. kiln_ai/utils/test_open_ai_types.py +131 -0
  85. {kiln_ai-0.18.0.dist-info → kiln_ai-0.20.1.dist-info}/METADATA +37 -6
  86. kiln_ai-0.20.1.dist-info/RECORD +138 -0
  87. kiln_ai-0.18.0.dist-info/RECORD +0 -115
  88. {kiln_ai-0.18.0.dist-info → kiln_ai-0.20.1.dist-info}/WHEEL +0 -0
  89. {kiln_ai-0.18.0.dist-info → kiln_ai-0.20.1.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,17 @@
1
+ from kiln_ai.datamodel.project import Project
2
+ from kiln_ai.utils.config import Config
3
+
4
+
5
+ def project_from_id(project_id: str) -> Project | None:
6
+ project_paths = Config.shared().projects
7
+ if project_paths is not None:
8
+ for project_path in project_paths:
9
+ try:
10
+ project = Project.load_from_file(project_path)
11
+ if project.id == project_id:
12
+ return project
13
+ except Exception:
14
+ # deleted files are possible continue with the rest
15
+ continue
16
+
17
+ return None
@@ -6,7 +6,7 @@ from unittest.mock import patch
6
6
  import pytest
7
7
  import yaml
8
8
 
9
- from kiln_ai.utils.config import Config, ConfigProperty, _get_user_id
9
+ from kiln_ai.utils.config import MCP_SECRETS_KEY, Config, ConfigProperty, _get_user_id
10
10
 
11
11
 
12
12
  @pytest.fixture
@@ -322,3 +322,140 @@ def test_update_settings_thread_safety(config_with_yaml):
322
322
 
323
323
  assert not exceptions
324
324
  assert config.int_property in range(5)
325
+
326
+
327
+ def test_mcp_secrets_property():
328
+ """Test mcp_secrets configuration property"""
329
+ config = Config.shared()
330
+
331
+ # Initially should be None/empty
332
+ assert config.mcp_secrets is None
333
+
334
+ # Set some secrets
335
+ secrets = {
336
+ "server1::Authorization": "Bearer token123",
337
+ "server1::X-API-Key": "api-key-456",
338
+ "server2::Token": "secret-token",
339
+ }
340
+ config.mcp_secrets = secrets
341
+
342
+ # Verify they are stored correctly
343
+ assert config.mcp_secrets == secrets
344
+ assert config.mcp_secrets["server1::Authorization"] == "Bearer token123"
345
+ assert config.mcp_secrets["server1::X-API-Key"] == "api-key-456"
346
+ assert config.mcp_secrets["server2::Token"] == "secret-token"
347
+
348
+
349
+ def test_mcp_secrets_sensitive_hiding():
350
+ """Test that mcp_secrets are hidden when hide_sensitive=True"""
351
+ config = Config.shared()
352
+
353
+ # Set some secrets
354
+ secrets = {
355
+ "server1::Authorization": "Bearer secret123",
356
+ "server2::X-API-Key": "secret-key",
357
+ }
358
+ config.mcp_secrets = secrets
359
+
360
+ # Test without hiding sensitive data
361
+ visible_settings = config.settings(hide_sensitive=False)
362
+ assert MCP_SECRETS_KEY in visible_settings
363
+ assert visible_settings[MCP_SECRETS_KEY] == secrets
364
+
365
+ # Test with hiding sensitive data
366
+ hidden_settings = config.settings(hide_sensitive=True)
367
+ assert MCP_SECRETS_KEY in hidden_settings
368
+ assert hidden_settings[MCP_SECRETS_KEY] == "[hidden]"
369
+
370
+
371
+ def test_mcp_secrets_persistence(mock_yaml_file):
372
+ """Test that mcp_secrets are persisted to YAML correctly"""
373
+ with patch(
374
+ "kiln_ai.utils.config.Config.settings_path",
375
+ return_value=mock_yaml_file,
376
+ ):
377
+ config = Config()
378
+
379
+ # Set some secrets
380
+ secrets = {
381
+ "server1::Authorization": "Bearer persist123",
382
+ "server2::Token": "persist-token",
383
+ }
384
+ config.mcp_secrets = secrets
385
+
386
+ # Check that the value was saved to the YAML file
387
+ with open(mock_yaml_file, "r") as f:
388
+ saved_settings = yaml.safe_load(f)
389
+ assert saved_settings[MCP_SECRETS_KEY] == secrets
390
+
391
+ # Create a new config instance to test loading from YAML
392
+ new_config = Config()
393
+
394
+ # Check that the value is loaded from YAML
395
+ assert new_config.mcp_secrets == secrets
396
+
397
+
398
+ def test_mcp_secrets_get_value():
399
+ """Test that mcp_secrets can be retrieved using get_value method"""
400
+ config = Config.shared()
401
+
402
+ # Initially should be None
403
+ assert config.get_value(MCP_SECRETS_KEY) is None
404
+
405
+ # Set some secrets
406
+ secrets = {"server::key": "value"}
407
+ config.mcp_secrets = secrets
408
+
409
+ # Should be retrievable via get_value
410
+ assert config.get_value(MCP_SECRETS_KEY) == secrets
411
+
412
+
413
+ def test_mcp_secrets_update_settings():
414
+ """Test updating mcp_secrets using update_settings method"""
415
+ config = Config.shared()
416
+
417
+ # Set initial secrets
418
+ initial_secrets = {"server1::key1": "value1"}
419
+ config.update_settings({MCP_SECRETS_KEY: initial_secrets})
420
+ assert config.mcp_secrets == initial_secrets
421
+
422
+ # Update with new secrets (should replace, not merge)
423
+ new_secrets = {
424
+ "server1::key1": "updated_value1",
425
+ "server2::key2": "value2",
426
+ }
427
+ config.update_settings({MCP_SECRETS_KEY: new_secrets})
428
+ assert config.mcp_secrets == new_secrets
429
+ assert config.mcp_secrets["server1::key1"] == "updated_value1"
430
+ assert config.mcp_secrets["server2::key2"] == "value2"
431
+
432
+
433
+ def test_mcp_secrets_empty_dict():
434
+ """Test mcp_secrets with empty dict"""
435
+ config = Config.shared()
436
+
437
+ # Set empty dict
438
+ config.mcp_secrets = {}
439
+ assert config.mcp_secrets == {}
440
+
441
+ # Should still be dict type, not None
442
+ assert isinstance(config.mcp_secrets, dict)
443
+
444
+
445
+ def test_mcp_secrets_type_validation():
446
+ """Test that mcp_secrets enforces dict[str, str] type"""
447
+ config = Config.shared()
448
+
449
+ # Valid dict[str, str]
450
+ valid_secrets = {"server::key": "value"}
451
+ config.mcp_secrets = valid_secrets
452
+ assert config.mcp_secrets == valid_secrets
453
+
454
+ # The config system applies type conversion when retrieving values
455
+ mixed_types = {"server::key": 123} # int value
456
+ config.mcp_secrets = mixed_types
457
+ # The type conversion happens when the value is retrieved, not when set
458
+ # So the underlying storage may preserve the original type
459
+ assert config.mcp_secrets == mixed_types or config.mcp_secrets == {
460
+ "server::key": "123"
461
+ }
@@ -0,0 +1,131 @@
1
+ """Tests for OpenAI types wrapper to ensure compatibility."""
2
+
3
+ from typing import get_args, get_origin
4
+
5
+ from openai.types.chat import (
6
+ ChatCompletionAssistantMessageParam as OpenAIChatCompletionAssistantMessageParam,
7
+ )
8
+ from openai.types.chat import (
9
+ ChatCompletionMessageParam as OpenAIChatCompletionMessageParam,
10
+ )
11
+
12
+ from kiln_ai.utils.open_ai_types import (
13
+ ChatCompletionAssistantMessageParamWrapper,
14
+ )
15
+ from kiln_ai.utils.open_ai_types import (
16
+ ChatCompletionMessageParam as KilnChatCompletionMessageParam,
17
+ )
18
+
19
+
20
+ def test_assistant_message_param_properties_match():
21
+ """
22
+ Test that ChatCompletionAssistantMessageParamWrapper has all the same properties
23
+ as OpenAI's ChatCompletionAssistantMessageParam, except for the known tool_calls type difference.
24
+
25
+ This will catch any changes to the OpenAI types that we haven't updated our wrapper for.
26
+ """
27
+ # Get annotations for both types
28
+ openai_annotations = OpenAIChatCompletionAssistantMessageParam.__annotations__
29
+ kiln_annotations = ChatCompletionAssistantMessageParamWrapper.__annotations__
30
+
31
+ # Check that both have the same property names
32
+ openai_properties = set(openai_annotations.keys())
33
+ kiln_properties = set(kiln_annotations.keys())
34
+
35
+ # Reasoning content is an added property. Confirm it's there and remove it from the comparison.
36
+ assert "reasoning_content" in kiln_properties, "Kiln should have reasoning_content"
37
+ kiln_properties.remove("reasoning_content")
38
+
39
+ assert openai_properties == kiln_properties, (
40
+ f"Property names don't match. "
41
+ f"OpenAI has: {openai_properties}, "
42
+ f"Kiln has: {kiln_properties}, "
43
+ f"Missing from Kiln: {openai_properties - kiln_properties}, "
44
+ f"Extra in Kiln: {kiln_properties - openai_properties}"
45
+ )
46
+
47
+
48
+ def test_chat_completion_message_param_union_compatibility():
49
+ """
50
+ Test that our ChatCompletionMessageParam union contains the same types as OpenAI's,
51
+ except with our wrapper instead of the original assistant message param.
52
+ """
53
+ # Get the union members for both types
54
+ openai_union_args = get_args(OpenAIChatCompletionMessageParam)
55
+ kiln_union_args = get_args(KilnChatCompletionMessageParam)
56
+
57
+ # Both should be unions with the same number of members
58
+ assert get_origin(OpenAIChatCompletionMessageParam) == get_origin(
59
+ KilnChatCompletionMessageParam
60
+ ), (
61
+ f"Both should be Union types. OpenAI: {get_origin(OpenAIChatCompletionMessageParam)}, "
62
+ f"Kiln: {get_origin(KilnChatCompletionMessageParam)}"
63
+ )
64
+ assert len(openai_union_args) == len(kiln_union_args), (
65
+ f"Union member count mismatch. OpenAI has {len(openai_union_args)} members, "
66
+ f"Kiln has {len(kiln_union_args)} members"
67
+ )
68
+
69
+ # Convert to sets of type names for easier comparison
70
+ openai_type_names = {arg.__name__ for arg in openai_union_args}
71
+ kiln_type_names = {arg.__name__ for arg in kiln_union_args}
72
+
73
+ # Expected difference: OpenAI has ChatCompletionAssistantMessageParam,
74
+ # Kiln has ChatCompletionAssistantMessageParamWrapper
75
+ expected_openai_only = {"ChatCompletionAssistantMessageParam"}
76
+ expected_kiln_only = {"ChatCompletionAssistantMessageParamWrapper"}
77
+
78
+ openai_only = openai_type_names - kiln_type_names
79
+ kiln_only = kiln_type_names - openai_type_names
80
+
81
+ assert openai_only == expected_openai_only, (
82
+ f"Unexpected types only in OpenAI union: {openai_only - expected_openai_only}"
83
+ )
84
+ assert kiln_only == expected_kiln_only, (
85
+ f"Unexpected types only in Kiln union: {kiln_only - expected_kiln_only}"
86
+ )
87
+
88
+ # All other types should be identical
89
+ common_types = openai_type_names & kiln_type_names
90
+ expected_common_types = {
91
+ "ChatCompletionDeveloperMessageParam",
92
+ "ChatCompletionSystemMessageParam",
93
+ "ChatCompletionUserMessageParam",
94
+ "ChatCompletionToolMessageParam",
95
+ "ChatCompletionFunctionMessageParam",
96
+ }
97
+
98
+ assert common_types == expected_common_types, (
99
+ f"Common types mismatch. Expected: {expected_common_types}, Got: {common_types}"
100
+ )
101
+
102
+
103
+ def test_wrapper_can_be_instantiated():
104
+ """Test that our wrapper can be instantiated with the same data as the original."""
105
+ # Create a sample message that should work with both types
106
+ sample_message: ChatCompletionAssistantMessageParamWrapper = {
107
+ "role": "assistant",
108
+ "content": "Hello, world!",
109
+ }
110
+
111
+ # This should work without type errors (runtime test)
112
+ assert sample_message["role"] == "assistant"
113
+ assert sample_message.get("content") == "Hello, world!"
114
+
115
+ # Test with tool calls using List instead of Iterable
116
+ sample_with_tools: ChatCompletionAssistantMessageParamWrapper = {
117
+ "role": "assistant",
118
+ "content": "I'll help you with that.",
119
+ "tool_calls": [
120
+ {
121
+ "id": "call_123",
122
+ "type": "function",
123
+ "function": {"name": "test_function", "arguments": '{"arg": "value"}'},
124
+ }
125
+ ],
126
+ }
127
+
128
+ assert len(sample_with_tools.get("tool_calls", [])) == 1
129
+ tool_calls = sample_with_tools.get("tool_calls", [])
130
+ if tool_calls:
131
+ assert tool_calls[0]["id"] == "call_123"
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kiln-ai
3
- Version: 0.18.0
3
+ Version: 0.20.1
4
4
  Summary: Kiln AI
5
- Project-URL: Homepage, https://getkiln.ai
5
+ Project-URL: Homepage, https://kiln.tech
6
6
  Project-URL: Repository, https://github.com/Kiln-AI/kiln
7
7
  Project-URL: Documentation, https://kiln-ai.github.io/Kiln/kiln_core_docs/kiln_ai.html
8
8
  Project-URL: Issues, https://github.com/Kiln-AI/kiln/issues
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.13
17
17
  Requires-Python: >=3.10
18
18
  Requires-Dist: boto3>=1.37.10
19
19
  Requires-Dist: coverage>=7.6.4
20
+ Requires-Dist: exceptiongroup>=1.0.0; python_version < '3.11'
20
21
  Requires-Dist: google-cloud-aiplatform>=1.84.0
21
22
  Requires-Dist: jsonschema>=4.23.0
22
23
  Requires-Dist: litellm>=1.72.6
@@ -53,7 +54,7 @@ pip install kiln_ai
53
54
 
54
55
  ## About
55
56
 
56
- This package is the Kiln AI core library. There is also a separate desktop application and server package. Learn more about Kiln AI at [getkiln.ai](https://getkiln.ai) and on Github: [github.com/Kiln-AI/kiln](https://github.com/Kiln-AI/kiln).
57
+ This package is the Kiln AI core library. There is also a separate desktop application and server package. Learn more about Kiln AI at [kiln.tech](https://kiln.tech) and on Github: [github.com/Kiln-AI/kiln](https://github.com/Kiln-AI/kiln).
57
58
 
58
59
  # Guide: Using the Kiln Python Library
59
60
 
@@ -65,6 +66,7 @@ The library has a [comprehensive set of docs](https://kiln-ai.github.io/Kiln/kil
65
66
 
66
67
  ## Table of Contents
67
68
 
69
+ - [Connecting AI Providers](#connecting-ai-providers-openai-openrouter-ollama-etc)
68
70
  - [Using the Kiln Data Model](#using-the-kiln-data-model)
69
71
  - [Understanding the Kiln Data Model](#understanding-the-kiln-data-model)
70
72
  - [Datamodel Overview](#datamodel-overview)
@@ -73,6 +75,7 @@ The library has a [comprehensive set of docs](https://kiln-ai.github.io/Kiln/kil
73
75
  - [Using your Kiln Dataset in a Notebook or Project](#using-your-kiln-dataset-in-a-notebook-or-project)
74
76
  - [Using Kiln Dataset in Pandas](#using-kiln-dataset-in-pandas)
75
77
  - [Building and Running a Kiln Task from Code](#building-and-running-a-kiln-task-from-code)
78
+ - [Tagging Task Runs Programmatically](#tagging-task-runs-programmatically)
76
79
  - [Adding Custom Model or AI Provider from Code](#adding-custom-model-or-ai-provider-from-code)
77
80
  - [Full API Reference](#full-api-reference)
78
81
 
@@ -82,6 +85,12 @@ The library has a [comprehensive set of docs](https://kiln-ai.github.io/Kiln/kil
82
85
  pip install kiln-ai
83
86
  ```
84
87
 
88
+ ## Connecting AI Providers (OpenAI, OpenRouter, Ollama, etc)
89
+
90
+ The easiest way to connect AI providers is to use the Kiln app UI. Once connected in the UI, credentials will be stored to `~/.kiln_ai/settings.yml`, which will be available to the library.
91
+
92
+ For configuring credentials from code or connecting custom servers/model, see [Adding Custom Model or AI Provider from Code](#adding-custom-model-or-ai-provider-from-code).
93
+
85
94
  ## Using the Kiln Data Model
86
95
 
87
96
  ### Understanding the Kiln Data Model
@@ -179,7 +188,10 @@ item = kiln_ai.datamodel.TaskRun(
179
188
  type=kiln_ai.datamodel.DataSourceType.human,
180
189
  properties={"created_by": "Jane Doe"},
181
190
  ),
182
- rating=kiln_ai.datamodel.TaskOutputRating(score=5,type="five_star"),
191
+ rating=kiln_ai.datamodel.TaskOutputRating(
192
+ value=5,
193
+ type=kiln_ai.datamodel.datamodel_enums.five_star,
194
+ ),
183
195
  ),
184
196
  )
185
197
  item.save_to_file()
@@ -270,14 +282,33 @@ for run in task.runs():
270
282
 
271
283
  ```
272
284
 
285
+ ## Tagging Task Runs Programmatically
286
+
287
+ You can also tag your Kiln Task runs programmatically:
288
+
289
+ ```py
290
+ # Load your Kiln Task from disk
291
+ task_path = "/Users/youruser/Kiln Projects/test project/tasks/632780983478 - Joke Generator/task.kiln"
292
+ task = kiln_ai.datamodel.Task.load_from_file(task_path)
293
+
294
+ for run in task.runs():
295
+ # Parse the task output from JSON
296
+ output = json.loads(run.output.output)
297
+
298
+ # Add a tag if the punchline is unusually short
299
+ if len(output["punchline"]) < 100:
300
+ run.tags.append("very_short")
301
+ run.save_to_file() # Persist the updated tags
302
+ ```
303
+
273
304
  ### Adding Custom Model or AI Provider from Code
274
305
 
275
306
  You can add additional AI models and providers to Kiln.
276
307
 
277
308
  See our docs for more information, including how to add these from the UI:
278
309
 
279
- - [Custom Models From Existing Providers](https://docs.getkiln.ai/docs/models-and-ai-providers#custom-models-from-existing-providers)
280
- - [Custom OpenAI Compatible Servers](https://docs.getkiln.ai/docs/models-and-ai-providers#custom-openai-compatible-servers)
310
+ - [Custom Models From Existing Providers](https://docs.kiln.tech/docs/models-and-ai-providers#custom-models-from-existing-providers)
311
+ - [Custom OpenAI Compatible Servers](https://docs.kiln.tech/docs/models-and-ai-providers#custom-openai-compatible-servers)
281
312
 
282
313
  You can also add these from code. The kiln_ai.utils.Config class helps you manage the Kiln config file (stored at `~/.kiln_settings/config.yaml`):
283
314
 
@@ -0,0 +1,138 @@
1
+ kiln_ai/__init__.py,sha256=Sc4z8LRVFMwJUoc_DPVUriSXTZ6PO9MaJ80PhRbKyB8,34
2
+ kiln_ai/adapters/__init__.py,sha256=x36QTK8bkADA8FtqXhWU7fjWCnOCpm28QvyQQ-MOt4Q,1027
3
+ kiln_ai/adapters/adapter_registry.py,sha256=ZkQ5A1u9DD1hvMR6vxt1a44QOFzrpXbzexG7NMGWREU,10574
4
+ kiln_ai/adapters/docker_model_runner_tools.py,sha256=GOX_qwg2BNZp20cgota7iSW0YIdSqRHCleAYjIAGwws,3957
5
+ kiln_ai/adapters/ml_model_list.py,sha256=hYt--lQwz8Mdtf5U3wKsYf3w9YnRLiXuQULzqbHlxJo,135078
6
+ kiln_ai/adapters/ollama_tools.py,sha256=uObtLWfqKb9RXHN-TGGw2Y1FQlEMe0u8FgszI0zQn6U,3550
7
+ kiln_ai/adapters/prompt_builders.py,sha256=R5IgZ7I2Ftx7i67xQb9UwcHE5gbPxgvgys_UAs3fc6A,15165
8
+ kiln_ai/adapters/provider_tools.py,sha256=VCvtwjaLBYRBuOBuTUG_GAxV_Adw2sgdHNYsULoFYlY,17744
9
+ kiln_ai/adapters/remote_config.py,sha256=qXRjXVoF_f31XomSGdOdFyZL-_fNO66rp8JK5Wji1PE,3954
10
+ kiln_ai/adapters/run_output.py,sha256=QDBP14i5F6YsH3ymJp1V-3JijbNVd9BQ656WLVUGx1g,383
11
+ kiln_ai/adapters/test_adapter_registry.py,sha256=ubGU-H809EOsHkq3E4UrvsTf18zGePE_I3tEA2uG69o,12753
12
+ kiln_ai/adapters/test_docker_model_runner_tools.py,sha256=xv8cDZ1LPfqjSoLtakEPet6jwHvZ14dtyjzWXWM6pYM,10795
13
+ kiln_ai/adapters/test_ml_model_list.py,sha256=QbSz4jGpCQ4T5jiunBwslb_MrlgzNCD85Op6mYGjsJk,9698
14
+ kiln_ai/adapters/test_ollama_tools.py,sha256=xAUzL0IVmmXadVehJu1WjqbhpKEYGAgGt3pWx7hrubc,2514
15
+ kiln_ai/adapters/test_prompt_adaptors.py,sha256=4b3tn57RoPGDzz-L19hO3HQIt8KRQOEIH4nynLZGNn4,8426
16
+ kiln_ai/adapters/test_prompt_builders.py,sha256=SqGkluKZd7m7SPuq64NAprG0db11RDqoYai1m-1QgeQ,22585
17
+ kiln_ai/adapters/test_provider_tools.py,sha256=juaRAOqh_iZskb4xeyc-bkW_sOM3qDmZTaVTzUOdCoU,34675
18
+ kiln_ai/adapters/test_remote_config.py,sha256=BDcW9eHBFGdcbK0dpBb2MZh6gGXtkYsrWA6noeeXwAE,20571
19
+ kiln_ai/adapters/chat/__init__.py,sha256=ELydKUGeCcTiBJogzZUT8VXqr5kDtmoB8_GoyO28qR0,192
20
+ kiln_ai/adapters/chat/chat_formatter.py,sha256=_q9z2IvRD-Xr0b5NKfj9kNWCzW2k77zvRpEGn_qd--0,8337
21
+ kiln_ai/adapters/chat/test_chat_formatter.py,sha256=gzMOOsHgHAAlcgmgfVWkrTztPviBzsl8sZac2w06i_s,4721
22
+ kiln_ai/adapters/data_gen/__init__.py,sha256=QTZWaf7kq5BorhPvexJfwDEKmjRmIbhwW9ei8LW2SIs,276
23
+ kiln_ai/adapters/data_gen/data_gen_prompts.py,sha256=06gqU7uJDBr-G-txeGV9a4_NgKlbxDxhcylWclcVVxg,8792
24
+ kiln_ai/adapters/data_gen/data_gen_task.py,sha256=El-5Dad65JvYkgr9Q40LfdAQ7IUx9BIjxF5c_j8sEq0,7121
25
+ kiln_ai/adapters/data_gen/test_data_gen_task.py,sha256=nIuyJkYWsg9VUaLh95csrx8CnA3d8ivwmPjqTnOoz4Q,21308
26
+ kiln_ai/adapters/eval/__init__.py,sha256=0ptbK0ZxWuraxGn_WMgmE1tcaq0k5t-g-52kVohvWCg,693
27
+ kiln_ai/adapters/eval/base_eval.py,sha256=gi70nH4Ob1tMyUtjj1u2_9Vx8F4xjLmceyvqQinf0Ro,7496
28
+ kiln_ai/adapters/eval/eval_runner.py,sha256=PlFaFIwrPqzmpSbaJEpNxwPBJ1V_24oJUUIEGI7NcAw,9037
29
+ kiln_ai/adapters/eval/g_eval.py,sha256=3IAznqD0ZfZb9HoEv0-EDxTW9NU-OsG6MqV67Qo3kIs,16303
30
+ kiln_ai/adapters/eval/registry.py,sha256=gZ_s0VgEx79Fswkgi1tS4yOl7lzpkvUBJZ62RldhM_w,626
31
+ kiln_ai/adapters/eval/test_base_eval.py,sha256=gk7eBaNLXBxhwO1hGLM2fPzeuk12xFVd9TOwNQ9E9tA,16003
32
+ kiln_ai/adapters/eval/test_eval_runner.py,sha256=vSDlYo_ujB1EReCLUZlcnqNaamG2wB9QRil_X_oTEm0,18587
33
+ kiln_ai/adapters/eval/test_g_eval.py,sha256=kzfJUP_oEIippd1hETSjWyg8J4QU5cabUYzVb9n2MXY,20989
34
+ kiln_ai/adapters/eval/test_g_eval_data.py,sha256=9IIQE6YNmf-epogQapJloocTMSpF4dkTIeEEsgF474U,27805
35
+ kiln_ai/adapters/fine_tune/__init__.py,sha256=l3ZV8c_IhvLxdPRcbfs67nvqLbCM1fWqFIm3u3oPQpI,257
36
+ kiln_ai/adapters/fine_tune/base_finetune.py,sha256=4mLrFHvERU76_e8bCuOGLTc5UAdFn4UUCuPAe_3uD0Q,5875
37
+ kiln_ai/adapters/fine_tune/dataset_formatter.py,sha256=oWYXOdkRaVZR_mIeox2gLf5_LZJ79hHV9PThk82zHtU,12928
38
+ kiln_ai/adapters/fine_tune/finetune_registry.py,sha256=9RJLjviSoN3dQnKJE9Ss7df7dtdJgbuShB8IUcI-q9k,726
39
+ kiln_ai/adapters/fine_tune/fireworks_finetune.py,sha256=WuC2zkZQTD6msew81Dd6GMT6OV5mAl33_K9K7Os_OBY,20833
40
+ kiln_ai/adapters/fine_tune/openai_finetune.py,sha256=DjRn3HIY7whBDYTw2MqiwnTYRu4G4hJ85MXZB-_S-FY,8868
41
+ kiln_ai/adapters/fine_tune/test_base_finetune.py,sha256=atZI54SC6mVili5dEIuqwv2groLCZWYKSMzDZYjbUxQ,10705
42
+ kiln_ai/adapters/fine_tune/test_dataset_formatter.py,sha256=OmF3jW78FBHvDes6lusY8hWgLLHz5XBgHdDVWv2ccAI,29898
43
+ kiln_ai/adapters/fine_tune/test_fireworks_tinetune.py,sha256=Xq89amS0VyYP8zi8YteTudYHhykEK7-BZXOsIo_7uKE,37146
44
+ kiln_ai/adapters/fine_tune/test_openai_finetune.py,sha256=7Nf0rw2T-qMiPt1HEjkq2pxRd4IEJf_qzS1NrqZ12wk,19950
45
+ kiln_ai/adapters/fine_tune/test_together_finetune.py,sha256=ZwYmT4pPkhU-45Q-5fs4WL16dQ4OyvI7KXPevsrA24E,18122
46
+ kiln_ai/adapters/fine_tune/test_vertex_finetune.py,sha256=DBQbNUgpqDEvjjk7eHwBvDXPCEkhf4yfUw8QPi5fFPE,19178
47
+ kiln_ai/adapters/fine_tune/together_finetune.py,sha256=KpJBZt0NBNUNLsVEYYC4Dzob1jnlOFQnVI8Q-4kY9d8,14766
48
+ kiln_ai/adapters/fine_tune/vertex_finetune.py,sha256=Ik6Ov711-oruJnMHpVZTPimWJY2W_JnfdKIdR2djGrc,8545
49
+ kiln_ai/adapters/model_adapters/__init__.py,sha256=m5GRtOHwVVvp_XDOss8c1X3NFf1wQQlC2eBgI4tXQhM,212
50
+ kiln_ai/adapters/model_adapters/base_adapter.py,sha256=6aktTD3vSTLxVYVpKK0IhhLpjQCHgvBFSpo8T2hJ6To,14749
51
+ kiln_ai/adapters/model_adapters/litellm_adapter.py,sha256=uBU7JmonJKgu84ZcQdBgwy_wLiiLwCjw6B7rLOtNb-4,31136
52
+ kiln_ai/adapters/model_adapters/litellm_config.py,sha256=zOQEkYKeoQ0FIbxTkyyoaGtaQiB9eYK3IuyUgqSwzLE,485
53
+ kiln_ai/adapters/model_adapters/test_base_adapter.py,sha256=jCsBnhScr1jurugm80Bf_7w26A7RMb2uIUW8MndN4p8,22191
54
+ kiln_ai/adapters/model_adapters/test_litellm_adapter.py,sha256=Njw94NScXsIQ7upi5VRiRHWQeT20Ud2Vspcsy53BEHc,34303
55
+ kiln_ai/adapters/model_adapters/test_litellm_adapter_tools.py,sha256=wegq-zYDFf3YTnOAH2OkCR8Y43H2dTDtDa4k_RqeOCc,40231
56
+ kiln_ai/adapters/model_adapters/test_saving_adapter_results.py,sha256=9XFa4L3ZBbD0kKi_TzoGEIx-0aYaaVUmI24KRmzK8MU,9719
57
+ kiln_ai/adapters/model_adapters/test_structured_output.py,sha256=96jOlck177_ftq5i5nEq6-QyhuaAD6Ui9ZIe4dMUBoo,17200
58
+ kiln_ai/adapters/parsers/__init__.py,sha256=1eAJmjSfVShnC7batg2ZnBX0rARDDNdredLMYxmwoiA,202
59
+ kiln_ai/adapters/parsers/base_parser.py,sha256=AE8UYCttmVXbilpICotnDdFYTFhGMiBJHrxIUgPTAWM,280
60
+ kiln_ai/adapters/parsers/json_parser.py,sha256=IszrBrhIFrrVr76UZsuejkBdqpZG27mU72264HVgVzE,1274
61
+ kiln_ai/adapters/parsers/parser_registry.py,sha256=BbY12zbXj-FgdJ8WqEcBLg26WXoDk2fmriLRo2LYCSk,710
62
+ kiln_ai/adapters/parsers/r1_parser.py,sha256=fbO-Ab2CVj6K756GaLGwNL6kkNqBBq7dWHtenL1oiNI,3559
63
+ kiln_ai/adapters/parsers/request_formatters.py,sha256=NdZO8zcZy9tkea8JaD5c_OeoeVjoYYTG0GjwF812STw,1124
64
+ kiln_ai/adapters/parsers/test_json_parser.py,sha256=9kdWe_vRC5wjP8A1Ym6Zu6enDIz4ARCNiRpcZr7_3ak,1971
65
+ kiln_ai/adapters/parsers/test_parser_registry.py,sha256=FFJQgaKVu67yK4W7w_b26tuEYPPYGppfttJ0y5ctWUo,1041
66
+ kiln_ai/adapters/parsers/test_r1_parser.py,sha256=gj4N_JZmyBwZRqPDiGY0j30qQ1mrQhGrTuCRAgQv6_M,6306
67
+ kiln_ai/adapters/parsers/test_request_formatters.py,sha256=t3FlKT_Tte2u8zXJTMl8VaE8IrSzumuBysahbGesrbU,2090
68
+ kiln_ai/adapters/repair/__init__.py,sha256=dOO9MEpEhjiwzDVFg3MNfA2bKMPlax9iekDatpTkX8E,217
69
+ kiln_ai/adapters/repair/repair_task.py,sha256=ziOKNo2dT0a4ggLIDk5ETfSTbuxn_xgI60w1Ajd0sww,3286
70
+ kiln_ai/adapters/repair/test_repair_task.py,sha256=GLrEZsVt5Z-62NanVEtIvnI57YlS9GyhyNAr3ezW57o,8770
71
+ kiln_ai/datamodel/__init__.py,sha256=z07ivLErVBh0AZMorR_JPCk9N43OCEGr6jZt-GxmYSg,2022
72
+ kiln_ai/datamodel/basemodel.py,sha256=jyB351QSq6ll9JwzxCBaCY1aXNRp5nDF1dBdhVA6KRM,23871
73
+ kiln_ai/datamodel/datamodel_enums.py,sha256=0H_3rQEvfl3WAOlNdZ6mzC63qyrvSqYf4-SaHlZ6mNc,3908
74
+ kiln_ai/datamodel/dataset_filters.py,sha256=zXS5QeCqWa1vAxs3Pyy5FJtySx9yYJzxsCMANd23-3c,5502
75
+ kiln_ai/datamodel/dataset_split.py,sha256=dAqwwNtWhKntEGJtauT0-YDG8aLFISelYS7o8TWG0TE,5923
76
+ kiln_ai/datamodel/eval.py,sha256=vHDpwDBGUqveihu7bqsvPmcvuOKHTMBVd4a3zMbEo3s,15894
77
+ kiln_ai/datamodel/external_tool_server.py,sha256=lzf71nm8udH4GGdr3ABPGOpuLTd9mGrf2FmckSOh-wE,11983
78
+ kiln_ai/datamodel/finetune.py,sha256=3cwg9FTbhYDH2DEWS_L8lMS5KPok9mJItWjYHC6LnH0,4835
79
+ kiln_ai/datamodel/json_schema.py,sha256=vgzTVLrdjBm9h0XxYV54fP9wOcmsWvQhASG4yhK5eUY,3802
80
+ kiln_ai/datamodel/model_cache.py,sha256=9X4aAigbkFdytckgw8InCMh86uBna0ME_1HJSeMPEn0,4495
81
+ kiln_ai/datamodel/project.py,sha256=rm4JEwtr3Ctj2q1eYP4qJm7s9l-ser31TYf0TY1ei9c,1074
82
+ kiln_ai/datamodel/prompt.py,sha256=ZvqbycqP3XuEF7lXqCPTXlDHrS0OPZOUhU5T95_ns6M,1210
83
+ kiln_ai/datamodel/prompt_id.py,sha256=oBnU_j8g3Xnj8TJbgQAQfW7I4vcyna-pDxFbiLvPs74,2631
84
+ kiln_ai/datamodel/registry.py,sha256=RaIDmjrqzPe6SRKNVUUUCskqPseXcogi528W53jpAbc,477
85
+ kiln_ai/datamodel/run_config.py,sha256=sSHE0nlIoKrRQuqebSP6Vb2LYi0gHX3i3Bix1Vk4-xw,2166
86
+ kiln_ai/datamodel/strict_mode.py,sha256=sm4Xka8mnJHCShtbh6MMU5dDQv-cLj8lHgHkmFKpsl0,849
87
+ kiln_ai/datamodel/task.py,sha256=bR0Se7fVz1UzlGbzZpNfw_FERjdVvQKm16HH4Z-WxIE,6650
88
+ kiln_ai/datamodel/task_output.py,sha256=ILL5a7X_0FBqCOxboGA4rSlqDrtY_IFJJsgydny3CYs,13486
89
+ kiln_ai/datamodel/task_run.py,sha256=V7wlUXgq07EcLREa8VeIdN01wuzlvkvc16QYmLlgeGE,10325
90
+ kiln_ai/datamodel/test_basemodel.py,sha256=Nsu3jl81FlP-fkSRLKADah2rhaCb_09sdnZMxtkT3go,25270
91
+ kiln_ai/datamodel/test_dataset_filters.py,sha256=TFHQZLB0rJxnxsFjD546eXVFxZNAJi0sPZ8j24wYd1w,5322
92
+ kiln_ai/datamodel/test_dataset_split.py,sha256=mXB8udml_6U4BXR0xAGHsFINnhdcTDB1qhuZbQemk-w,11055
93
+ kiln_ai/datamodel/test_datasource.py,sha256=H4Kc-Im9eM7WnADWZXdoiOIrOl05RtkyuhTCKiRimyU,3905
94
+ kiln_ai/datamodel/test_eval_model.py,sha256=WbGWiIP4b6pu-Z117iVNsPLnrpFW2-sj89oOIQ8RLEk,23940
95
+ kiln_ai/datamodel/test_example_models.py,sha256=QoUdMHZfOT4BV0CyfBMLzJZo2vKi-rVw0gpWXYJCzOM,31407
96
+ kiln_ai/datamodel/test_external_tool_server.py,sha256=Ko_IAjEj7PyQL9z5ggTtcnwvOKZYx_xa-x1wdakWcRA,25154
97
+ kiln_ai/datamodel/test_json_schema.py,sha256=R0Cfc9WbieMslgvYsj2HFx8RHIq2fF9NcT5jH-kEqh4,4793
98
+ kiln_ai/datamodel/test_model_cache.py,sha256=Fy-ucYNzS5JEG-8SFY4nVHA8iRbXXxai20f8_oGl97o,8184
99
+ kiln_ai/datamodel/test_model_perf.py,sha256=JcJpedvgK49zj_VIUc5DW0QjuIXhaBQbBpccUJVy2hU,3319
100
+ kiln_ai/datamodel/test_models.py,sha256=wENuBiZ2Y-N_puFkitNZ1T-lBpVgQWotfhGug6k4AMY,21674
101
+ kiln_ai/datamodel/test_nested_save.py,sha256=xciCddqvPyKyoyjC5Lx_3Kh1t4LJv1xYRAPazR3SRcs,5588
102
+ kiln_ai/datamodel/test_output_rating.py,sha256=zvPIp2shAgCs2RQBgwYoL09fRA3krHvgAqUa91RlWR0,15125
103
+ kiln_ai/datamodel/test_prompt_id.py,sha256=_vcuiDvai8TENb6agk0F9ZsaTrAgoD1VkMxRIT2p9mQ,4384
104
+ kiln_ai/datamodel/test_registry.py,sha256=Y3dReO13QwGBaW9p7qUiTc0H-WaJ3pgapaN35kVoVD8,2903
105
+ kiln_ai/datamodel/test_task.py,sha256=4odjkdbkVZC-2En7o_dboDN7Segbh4yfz4Y3f7R7Dbc,10923
106
+ kiln_ai/datamodel/test_tool_id.py,sha256=VYF_cQP_Y5GPhEg9eIS_HEfOy9qUAPzjPCqvPO2SUp0,9186
107
+ kiln_ai/datamodel/tool_id.py,sha256=tv3PYA-2cqFthf7LTwcQADPsMHfvIq757-vcszm4PQs,2863
108
+ kiln_ai/tools/__init__.py,sha256=BaonknPnB9Z0QZligayytgrd8lqKXVOxX357YLW4Qw8,193
109
+ kiln_ai/tools/base_tool.py,sha256=f_aKjAyCsM39jjbF-yG2hz7QIc_LdZOK3WBWJ2neLr4,2359
110
+ kiln_ai/tools/mcp_server_tool.py,sha256=FwUzxcVsnNz0R-Skqelb6Q1xvFtpO2qc6Xxk7eFv-o8,3244
111
+ kiln_ai/tools/mcp_session_manager.py,sha256=VXHtjRHDJV1WBJZyQN9HxGH0EfaLE2TS5s5fSatgaEM,9445
112
+ kiln_ai/tools/test_base_tools.py,sha256=L0hziYZ2poMhF9_NOwycXS0WBdw41VF1cEN8kemGZtg,6542
113
+ kiln_ai/tools/test_mcp_server_tool.py,sha256=nIQgxcq5tuzjPzOwzRJskJYBrFkay5852jsAWbMqf6g,17337
114
+ kiln_ai/tools/test_mcp_session_manager.py,sha256=UjIONj4swQnxltS5vx6a0YunpI1Du5zZKQj15ts6OZQ,62486
115
+ kiln_ai/tools/test_tool_registry.py,sha256=6IMOaINFBnrtBMw-SG5eaCFUp1zH05DR6lrnRhrWMI8,19744
116
+ kiln_ai/tools/tool_registry.py,sha256=fkgPHP-rTnuJRcHjsC6cIEwAxKf03Wwz6hmkq1f-PDw,2218
117
+ kiln_ai/tools/built_in_tools/__init__.py,sha256=IGWLH55vk32KohEOy5lzM4mXb6cf43Rxm2XjLFtfve4,209
118
+ kiln_ai/tools/built_in_tools/math_tools.py,sha256=6OWEkkXYus36rSTW-31FGIAXxMGqILWyIIeDcUQOiMQ,3886
119
+ kiln_ai/tools/built_in_tools/test_math_tools.py,sha256=yYNpQYT1sGXjOT6ocNY01Ldp1IGPAiSypMioMLdYI-Q,6961
120
+ kiln_ai/utils/__init__.py,sha256=PTD0MwBCKAMIOGsTAwsFaJOusTJJoRFTfOGqRvCaU-E,142
121
+ kiln_ai/utils/async_job_runner.py,sha256=1gjoEq5yc2MOVjDo05O1wztguEuMC6l3haDZsltlvuw,3457
122
+ kiln_ai/utils/config.py,sha256=0b93Bg3NM_oL5EYQK6r5qUy6GQsiZyOfVDo3zFbWOT0,9652
123
+ kiln_ai/utils/dataset_import.py,sha256=EqBBBopCEUy1JH4-EAsBETwGp4MFjzZGfUUBZ6FLfGY,9011
124
+ kiln_ai/utils/exhaustive_error.py,sha256=TkkRixIAR3CPEKHeAJzyv0mtxp6BxUBKMvobA3vzQug,262
125
+ kiln_ai/utils/formatting.py,sha256=VtB9oag0lOGv17dwT7OPX_3HzBfaU9GsLH-iLete0yM,97
126
+ kiln_ai/utils/logging.py,sha256=ixtv2Mm6-XWB2PVUPAWVRXnPJULvoTDrsp5NTAk3yp0,6815
127
+ kiln_ai/utils/name_generator.py,sha256=v26TgpCwQbhQFcZvzgjZvURinjrOyyFhxpsI6NQrHKc,1914
128
+ kiln_ai/utils/open_ai_types.py,sha256=CH7EM9Y7b0o3fYradNGLzrWfmKkoYaHZWx8JUMLNJj8,2737
129
+ kiln_ai/utils/project_utils.py,sha256=C_4VpyHSO4a9yX6SKcL00-l8y1afriXuqvsh54pk6eU,566
130
+ kiln_ai/utils/test_async_job_runner.py,sha256=8AwPfOlR09qzfhVm-djpkmuoyHxJJ19QEzs0WV5KFSQ,6813
131
+ kiln_ai/utils/test_config.py,sha256=buu7On18fBqnpkHtku_LZCVGrgrTs87IulL5eLTMRK8,14112
132
+ kiln_ai/utils/test_dataset_import.py,sha256=BEl38D95HQYpc7_jeB1N-ocOnKM1DLutp669cNrVOuE,25765
133
+ kiln_ai/utils/test_name_geneator.py,sha256=9-hSTBshyakqlPbFnNcggwLrL7lcPTitauBYHg9jFWI,1513
134
+ kiln_ai/utils/test_open_ai_types.py,sha256=NCc3IoCXMq62u1uM2B0bfK3qKyp53y9jxyxvAjL_1X8,5231
135
+ kiln_ai-0.20.1.dist-info/METADATA,sha256=hKct9M2Q9WLU-OYDrbayYoNxjQtIPu2GyfE6OOPNnSQ,13564
136
+ kiln_ai-0.20.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
137
+ kiln_ai-0.20.1.dist-info/licenses/LICENSE.txt,sha256=_NA5pnTYgRRr4qH6lE3X-TuZJ8iRcMUi5ASoGr-lEx8,1209
138
+ kiln_ai-0.20.1.dist-info/RECORD,,