kiln-ai 0.19.0__py3-none-any.whl → 0.21.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 (158) hide show
  1. kiln_ai/adapters/__init__.py +8 -2
  2. kiln_ai/adapters/adapter_registry.py +43 -208
  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/chunkers/__init__.py +13 -0
  6. kiln_ai/adapters/chunkers/base_chunker.py +42 -0
  7. kiln_ai/adapters/chunkers/chunker_registry.py +16 -0
  8. kiln_ai/adapters/chunkers/fixed_window_chunker.py +39 -0
  9. kiln_ai/adapters/chunkers/helpers.py +23 -0
  10. kiln_ai/adapters/chunkers/test_base_chunker.py +63 -0
  11. kiln_ai/adapters/chunkers/test_chunker_registry.py +28 -0
  12. kiln_ai/adapters/chunkers/test_fixed_window_chunker.py +346 -0
  13. kiln_ai/adapters/chunkers/test_helpers.py +75 -0
  14. kiln_ai/adapters/data_gen/test_data_gen_task.py +9 -3
  15. kiln_ai/adapters/docker_model_runner_tools.py +119 -0
  16. kiln_ai/adapters/embedding/__init__.py +0 -0
  17. kiln_ai/adapters/embedding/base_embedding_adapter.py +44 -0
  18. kiln_ai/adapters/embedding/embedding_registry.py +32 -0
  19. kiln_ai/adapters/embedding/litellm_embedding_adapter.py +199 -0
  20. kiln_ai/adapters/embedding/test_base_embedding_adapter.py +283 -0
  21. kiln_ai/adapters/embedding/test_embedding_registry.py +166 -0
  22. kiln_ai/adapters/embedding/test_litellm_embedding_adapter.py +1149 -0
  23. kiln_ai/adapters/eval/base_eval.py +2 -2
  24. kiln_ai/adapters/eval/eval_runner.py +9 -3
  25. kiln_ai/adapters/eval/g_eval.py +2 -2
  26. kiln_ai/adapters/eval/test_base_eval.py +2 -4
  27. kiln_ai/adapters/eval/test_g_eval.py +4 -5
  28. kiln_ai/adapters/extractors/__init__.py +18 -0
  29. kiln_ai/adapters/extractors/base_extractor.py +72 -0
  30. kiln_ai/adapters/extractors/encoding.py +20 -0
  31. kiln_ai/adapters/extractors/extractor_registry.py +44 -0
  32. kiln_ai/adapters/extractors/extractor_runner.py +112 -0
  33. kiln_ai/adapters/extractors/litellm_extractor.py +386 -0
  34. kiln_ai/adapters/extractors/test_base_extractor.py +244 -0
  35. kiln_ai/adapters/extractors/test_encoding.py +54 -0
  36. kiln_ai/adapters/extractors/test_extractor_registry.py +181 -0
  37. kiln_ai/adapters/extractors/test_extractor_runner.py +181 -0
  38. kiln_ai/adapters/extractors/test_litellm_extractor.py +1192 -0
  39. kiln_ai/adapters/fine_tune/__init__.py +1 -1
  40. kiln_ai/adapters/fine_tune/openai_finetune.py +14 -4
  41. kiln_ai/adapters/fine_tune/test_dataset_formatter.py +2 -2
  42. kiln_ai/adapters/fine_tune/test_fireworks_tinetune.py +2 -6
  43. kiln_ai/adapters/fine_tune/test_openai_finetune.py +108 -111
  44. kiln_ai/adapters/fine_tune/test_together_finetune.py +2 -6
  45. kiln_ai/adapters/ml_embedding_model_list.py +192 -0
  46. kiln_ai/adapters/ml_model_list.py +761 -37
  47. kiln_ai/adapters/model_adapters/base_adapter.py +51 -21
  48. kiln_ai/adapters/model_adapters/litellm_adapter.py +380 -138
  49. kiln_ai/adapters/model_adapters/test_base_adapter.py +193 -17
  50. kiln_ai/adapters/model_adapters/test_litellm_adapter.py +407 -2
  51. kiln_ai/adapters/model_adapters/test_litellm_adapter_tools.py +1103 -0
  52. kiln_ai/adapters/model_adapters/test_saving_adapter_results.py +5 -5
  53. kiln_ai/adapters/model_adapters/test_structured_output.py +113 -5
  54. kiln_ai/adapters/ollama_tools.py +69 -12
  55. kiln_ai/adapters/parsers/__init__.py +1 -1
  56. kiln_ai/adapters/provider_tools.py +205 -47
  57. kiln_ai/adapters/rag/deduplication.py +49 -0
  58. kiln_ai/adapters/rag/progress.py +252 -0
  59. kiln_ai/adapters/rag/rag_runners.py +844 -0
  60. kiln_ai/adapters/rag/test_deduplication.py +195 -0
  61. kiln_ai/adapters/rag/test_progress.py +785 -0
  62. kiln_ai/adapters/rag/test_rag_runners.py +2376 -0
  63. kiln_ai/adapters/remote_config.py +80 -8
  64. kiln_ai/adapters/repair/test_repair_task.py +12 -9
  65. kiln_ai/adapters/run_output.py +3 -0
  66. kiln_ai/adapters/test_adapter_registry.py +657 -85
  67. kiln_ai/adapters/test_docker_model_runner_tools.py +305 -0
  68. kiln_ai/adapters/test_ml_embedding_model_list.py +429 -0
  69. kiln_ai/adapters/test_ml_model_list.py +251 -1
  70. kiln_ai/adapters/test_ollama_tools.py +340 -1
  71. kiln_ai/adapters/test_prompt_adaptors.py +13 -6
  72. kiln_ai/adapters/test_prompt_builders.py +1 -1
  73. kiln_ai/adapters/test_provider_tools.py +254 -8
  74. kiln_ai/adapters/test_remote_config.py +651 -58
  75. kiln_ai/adapters/vector_store/__init__.py +1 -0
  76. kiln_ai/adapters/vector_store/base_vector_store_adapter.py +83 -0
  77. kiln_ai/adapters/vector_store/lancedb_adapter.py +389 -0
  78. kiln_ai/adapters/vector_store/test_base_vector_store.py +160 -0
  79. kiln_ai/adapters/vector_store/test_lancedb_adapter.py +1841 -0
  80. kiln_ai/adapters/vector_store/test_vector_store_registry.py +199 -0
  81. kiln_ai/adapters/vector_store/vector_store_registry.py +33 -0
  82. kiln_ai/datamodel/__init__.py +39 -34
  83. kiln_ai/datamodel/basemodel.py +170 -1
  84. kiln_ai/datamodel/chunk.py +158 -0
  85. kiln_ai/datamodel/datamodel_enums.py +28 -0
  86. kiln_ai/datamodel/embedding.py +64 -0
  87. kiln_ai/datamodel/eval.py +1 -1
  88. kiln_ai/datamodel/external_tool_server.py +298 -0
  89. kiln_ai/datamodel/extraction.py +303 -0
  90. kiln_ai/datamodel/json_schema.py +25 -10
  91. kiln_ai/datamodel/project.py +40 -1
  92. kiln_ai/datamodel/rag.py +79 -0
  93. kiln_ai/datamodel/registry.py +0 -15
  94. kiln_ai/datamodel/run_config.py +62 -0
  95. kiln_ai/datamodel/task.py +2 -77
  96. kiln_ai/datamodel/task_output.py +6 -1
  97. kiln_ai/datamodel/task_run.py +41 -0
  98. kiln_ai/datamodel/test_attachment.py +649 -0
  99. kiln_ai/datamodel/test_basemodel.py +4 -4
  100. kiln_ai/datamodel/test_chunk_models.py +317 -0
  101. kiln_ai/datamodel/test_dataset_split.py +1 -1
  102. kiln_ai/datamodel/test_embedding_models.py +448 -0
  103. kiln_ai/datamodel/test_eval_model.py +6 -6
  104. kiln_ai/datamodel/test_example_models.py +175 -0
  105. kiln_ai/datamodel/test_external_tool_server.py +691 -0
  106. kiln_ai/datamodel/test_extraction_chunk.py +206 -0
  107. kiln_ai/datamodel/test_extraction_model.py +470 -0
  108. kiln_ai/datamodel/test_rag.py +641 -0
  109. kiln_ai/datamodel/test_registry.py +8 -3
  110. kiln_ai/datamodel/test_task.py +15 -47
  111. kiln_ai/datamodel/test_tool_id.py +320 -0
  112. kiln_ai/datamodel/test_vector_store.py +320 -0
  113. kiln_ai/datamodel/tool_id.py +105 -0
  114. kiln_ai/datamodel/vector_store.py +141 -0
  115. kiln_ai/tools/__init__.py +8 -0
  116. kiln_ai/tools/base_tool.py +82 -0
  117. kiln_ai/tools/built_in_tools/__init__.py +13 -0
  118. kiln_ai/tools/built_in_tools/math_tools.py +124 -0
  119. kiln_ai/tools/built_in_tools/test_math_tools.py +204 -0
  120. kiln_ai/tools/mcp_server_tool.py +95 -0
  121. kiln_ai/tools/mcp_session_manager.py +246 -0
  122. kiln_ai/tools/rag_tools.py +157 -0
  123. kiln_ai/tools/test_base_tools.py +199 -0
  124. kiln_ai/tools/test_mcp_server_tool.py +457 -0
  125. kiln_ai/tools/test_mcp_session_manager.py +1585 -0
  126. kiln_ai/tools/test_rag_tools.py +848 -0
  127. kiln_ai/tools/test_tool_registry.py +562 -0
  128. kiln_ai/tools/tool_registry.py +85 -0
  129. kiln_ai/utils/__init__.py +3 -0
  130. kiln_ai/utils/async_job_runner.py +62 -17
  131. kiln_ai/utils/config.py +24 -2
  132. kiln_ai/utils/env.py +15 -0
  133. kiln_ai/utils/filesystem.py +14 -0
  134. kiln_ai/utils/filesystem_cache.py +60 -0
  135. kiln_ai/utils/litellm.py +94 -0
  136. kiln_ai/utils/lock.py +100 -0
  137. kiln_ai/utils/mime_type.py +38 -0
  138. kiln_ai/utils/open_ai_types.py +94 -0
  139. kiln_ai/utils/pdf_utils.py +38 -0
  140. kiln_ai/utils/project_utils.py +17 -0
  141. kiln_ai/utils/test_async_job_runner.py +151 -35
  142. kiln_ai/utils/test_config.py +138 -1
  143. kiln_ai/utils/test_env.py +142 -0
  144. kiln_ai/utils/test_filesystem_cache.py +316 -0
  145. kiln_ai/utils/test_litellm.py +206 -0
  146. kiln_ai/utils/test_lock.py +185 -0
  147. kiln_ai/utils/test_mime_type.py +66 -0
  148. kiln_ai/utils/test_open_ai_types.py +131 -0
  149. kiln_ai/utils/test_pdf_utils.py +73 -0
  150. kiln_ai/utils/test_uuid.py +111 -0
  151. kiln_ai/utils/test_validation.py +524 -0
  152. kiln_ai/utils/uuid.py +9 -0
  153. kiln_ai/utils/validation.py +90 -0
  154. {kiln_ai-0.19.0.dist-info → kiln_ai-0.21.0.dist-info}/METADATA +12 -5
  155. kiln_ai-0.21.0.dist-info/RECORD +211 -0
  156. kiln_ai-0.19.0.dist-info/RECORD +0 -115
  157. {kiln_ai-0.19.0.dist-info → kiln_ai-0.21.0.dist-info}/WHEEL +0 -0
  158. {kiln_ai-0.19.0.dist-info → kiln_ai-0.21.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -6,7 +6,11 @@ from kiln_ai.adapters.ml_model_list import KilnModelProvider, StructuredOutputMo
6
6
  from kiln_ai.adapters.model_adapters.base_adapter import BaseAdapter, RunOutput
7
7
  from kiln_ai.datamodel import Task
8
8
  from kiln_ai.datamodel.datamodel_enums import ChatStrategy
9
- from kiln_ai.datamodel.task import RunConfig, RunConfigProperties
9
+ from kiln_ai.datamodel.project import Project
10
+ from kiln_ai.datamodel.run_config import ToolsRunConfig
11
+ from kiln_ai.datamodel.task import RunConfigProperties
12
+ from kiln_ai.datamodel.tool_id import KilnBuiltInToolId
13
+ from kiln_ai.tools.base_tool import KilnToolInterface
10
14
 
11
15
 
12
16
  class MockAdapter(BaseAdapter):
@@ -27,15 +31,21 @@ def mock_provider():
27
31
 
28
32
 
29
33
  @pytest.fixture
30
- def base_task():
31
- return Task(name="test_task", instruction="test_instruction")
34
+ def base_project():
35
+ return Project(name="test_project", description="test project description")
36
+
37
+
38
+ @pytest.fixture
39
+ def base_task(base_project):
40
+ task = Task(name="test_task", instruction="test_instruction", parent=base_project)
41
+ return task
32
42
 
33
43
 
34
44
  @pytest.fixture
35
45
  def adapter(base_task):
36
46
  return MockAdapter(
37
- run_config=RunConfig(
38
- task=base_task,
47
+ task=base_task,
48
+ run_config=RunConfigProperties(
39
49
  model_name="test_model",
40
50
  model_provider_name="openai",
41
51
  prompt_id="simple_prompt_builder",
@@ -98,13 +108,16 @@ async def test_model_provider_loads_and_caches(adapter, mock_provider):
98
108
  mock_loader.assert_not_called()
99
109
 
100
110
 
101
- async def test_model_provider_invalid_provider_model_name(base_task):
111
+ async def test_model_provider_invalid_provider_model_name(base_project):
102
112
  """Test error when model or provider name is missing"""
113
+ # Create a task with a parent project
114
+ task = Task(name="test_task", instruction="test_instruction", parent=base_project)
115
+
103
116
  # Test with missing model name
104
117
  with pytest.raises(ValueError, match="Input should be"):
105
118
  MockAdapter(
106
- run_config=RunConfig(
107
- task=base_task,
119
+ task=task,
120
+ run_config=RunConfigProperties(
108
121
  model_name="test_model",
109
122
  model_provider_name="invalid",
110
123
  prompt_id="simple_prompt_builder",
@@ -112,12 +125,15 @@ async def test_model_provider_invalid_provider_model_name(base_task):
112
125
  )
113
126
 
114
127
 
115
- async def test_model_provider_missing_model_names(base_task):
128
+ async def test_model_provider_missing_model_names(base_project):
116
129
  """Test error when model or provider name is missing"""
130
+ # Create a task with a parent project
131
+ task = Task(name="test_task", instruction="test_instruction", parent=base_project)
132
+
117
133
  # Test with missing model name
118
134
  adapter = MockAdapter(
119
- run_config=RunConfig(
120
- task=base_task,
135
+ task=task,
136
+ run_config=RunConfigProperties(
121
137
  model_name="",
122
138
  model_provider_name="openai",
123
139
  prompt_id="simple_prompt_builder",
@@ -252,12 +268,13 @@ async def test_properties_for_task_output_includes_all_run_config_properties(ada
252
268
  "temperature": "temperature",
253
269
  "top_p": "top_p",
254
270
  "structured_output_mode": "structured_output_mode",
271
+ "tools_config": None,
255
272
  }
256
273
 
257
274
  missing_properties = []
258
275
  for field_name in run_config_properties_fields:
259
276
  expected_key = expected_mappings.get(field_name, field_name)
260
- if expected_key not in saved_property_keys:
277
+ if expected_key is not None and expected_key not in saved_property_keys:
261
278
  missing_properties.append(
262
279
  f"RunConfigProperties.{field_name} -> {expected_key}"
263
280
  )
@@ -297,12 +314,13 @@ async def test_properties_for_task_output_catches_missing_new_property(adapter):
297
314
  "temperature": "temperature",
298
315
  "top_p": "top_p",
299
316
  "structured_output_mode": "structured_output_mode",
317
+ "tools_config": None,
300
318
  }
301
319
 
302
320
  missing_properties = []
303
321
  for field_name in run_config_properties_fields:
304
322
  expected_key = expected_mappings.get(field_name, field_name)
305
- if expected_key not in saved_property_keys:
323
+ if expected_key is not None and expected_key not in saved_property_keys:
306
324
  missing_properties.append(
307
325
  f"RunConfigProperties.{field_name} -> {expected_key}"
308
326
  )
@@ -408,12 +426,14 @@ def test_build_chat_formatter(
408
426
  ],
409
427
  )
410
428
  async def test_update_run_config_unknown_structured_output_mode(
411
- base_task, initial_mode, expected_mode
429
+ base_project, initial_mode, expected_mode
412
430
  ):
413
431
  """Test that unknown structured output mode is updated to the default for the model provider"""
432
+ # Create a task with a parent project
433
+ task = Task(name="test_task", instruction="test_instruction", parent=base_project)
434
+
414
435
  # Create a run config with the initial mode
415
- run_config = RunConfig(
416
- task=base_task,
436
+ run_config = RunConfigProperties(
417
437
  model_name="test_model",
418
438
  model_provider_name="openai",
419
439
  prompt_id="simple_prompt_builder",
@@ -429,7 +449,7 @@ async def test_update_run_config_unknown_structured_output_mode(
429
449
  mock_default.return_value = StructuredOutputMode.json_mode
430
450
 
431
451
  # Create the adapter
432
- adapter = MockAdapter(run_config=run_config)
452
+ adapter = MockAdapter(task=task, run_config=run_config)
433
453
 
434
454
  # Verify the mode was updated correctly
435
455
  assert adapter.run_config.structured_output_mode == expected_mode
@@ -443,3 +463,159 @@ async def test_update_run_config_unknown_structured_output_mode(
443
463
  mock_default.assert_called_once_with("test_model", "openai")
444
464
  else:
445
465
  mock_default.assert_not_called()
466
+
467
+
468
+ @pytest.mark.parametrize(
469
+ "tools_config,expected_tool_count,expected_tool_ids",
470
+ [
471
+ # No tools config
472
+ (None, 0, []),
473
+ # Empty tools config with None tools
474
+ (ToolsRunConfig(tools=[]), 0, []),
475
+ # Single tool
476
+ ([KilnBuiltInToolId.ADD_NUMBERS], 1, [KilnBuiltInToolId.ADD_NUMBERS]),
477
+ # Multiple tools
478
+ (
479
+ [KilnBuiltInToolId.ADD_NUMBERS, KilnBuiltInToolId.SUBTRACT_NUMBERS],
480
+ 2,
481
+ [KilnBuiltInToolId.ADD_NUMBERS, KilnBuiltInToolId.SUBTRACT_NUMBERS],
482
+ ),
483
+ # All available built-in tools
484
+ (
485
+ [
486
+ KilnBuiltInToolId.ADD_NUMBERS,
487
+ KilnBuiltInToolId.SUBTRACT_NUMBERS,
488
+ KilnBuiltInToolId.MULTIPLY_NUMBERS,
489
+ KilnBuiltInToolId.DIVIDE_NUMBERS,
490
+ ],
491
+ 4,
492
+ [
493
+ KilnBuiltInToolId.ADD_NUMBERS,
494
+ KilnBuiltInToolId.SUBTRACT_NUMBERS,
495
+ KilnBuiltInToolId.MULTIPLY_NUMBERS,
496
+ KilnBuiltInToolId.DIVIDE_NUMBERS,
497
+ ],
498
+ ),
499
+ ],
500
+ )
501
+ async def test_available_tools(
502
+ base_project, tools_config, expected_tool_count, expected_tool_ids
503
+ ):
504
+ """Test that available_tools returns correct tools based on tools_config"""
505
+ # Create a task with a parent project
506
+ task = Task(name="test_task", instruction="test_instruction", parent=base_project)
507
+
508
+ # Create tools config if we have tool IDs
509
+ if tools_config is None:
510
+ final_tools_config = None
511
+ elif isinstance(tools_config, list):
512
+ final_tools_config = ToolsRunConfig(tools=tools_config)
513
+ else:
514
+ final_tools_config = tools_config
515
+
516
+ # Create adapter with tools config
517
+ adapter = MockAdapter(
518
+ task=task,
519
+ run_config=RunConfigProperties(
520
+ model_name="test_model",
521
+ model_provider_name="openai",
522
+ prompt_id="simple_prompt_builder",
523
+ structured_output_mode="json_schema",
524
+ tools_config=final_tools_config,
525
+ ),
526
+ )
527
+
528
+ # Get available tools
529
+ tools = await adapter.available_tools()
530
+
531
+ # Verify tool count
532
+ assert len(tools) == expected_tool_count
533
+
534
+ # Verify all tools implement KilnToolInterface
535
+ for tool in tools:
536
+ assert isinstance(tool, KilnToolInterface)
537
+
538
+ # Verify tool IDs match expected
539
+ if expected_tool_ids:
540
+ actual_tool_ids = [await tool.id() for tool in tools]
541
+ assert actual_tool_ids == expected_tool_ids
542
+
543
+
544
+ async def test_available_tools_with_invalid_tool_id(base_project):
545
+ """Test that available_tools raises ValueError for invalid tool ID"""
546
+ # Create a task with a parent project
547
+ task = Task(name="test_task", instruction="test_instruction", parent=base_project)
548
+
549
+ # Create tools config with valid tool ID
550
+ tools_config = ToolsRunConfig(tools=[KilnBuiltInToolId.ADD_NUMBERS])
551
+
552
+ # Create adapter
553
+ adapter = MockAdapter(
554
+ task=task,
555
+ run_config=RunConfigProperties(
556
+ model_name="test_model",
557
+ model_provider_name="openai",
558
+ prompt_id="simple_prompt_builder",
559
+ structured_output_mode="json_schema",
560
+ tools_config=tools_config,
561
+ ),
562
+ )
563
+
564
+ # Mock tool_from_id to raise ValueError for any tool ID
565
+ with patch(
566
+ "kiln_ai.adapters.model_adapters.base_adapter.tool_from_id"
567
+ ) as mock_tool_from_id:
568
+ mock_tool_from_id.side_effect = ValueError(
569
+ "Tool ID test_id not found in tool registry"
570
+ )
571
+
572
+ # Should raise ValueError when trying to get tools
573
+ with pytest.raises(
574
+ ValueError, match="Tool ID test_id not found in tool registry"
575
+ ):
576
+ await adapter.available_tools()
577
+
578
+
579
+ async def test_available_tools_duplicate_names_raises_error(base_project):
580
+ """Test that available_tools raises ValueError when tools have duplicate names"""
581
+ # Create a task with a parent project
582
+ task = Task(name="test_task", instruction="test_instruction", parent=base_project)
583
+
584
+ # Create tools config with two different tool IDs
585
+ tools_config = ToolsRunConfig(
586
+ tools=[KilnBuiltInToolId.ADD_NUMBERS, KilnBuiltInToolId.SUBTRACT_NUMBERS]
587
+ )
588
+
589
+ # Create adapter
590
+ adapter = MockAdapter(
591
+ task=task,
592
+ run_config=RunConfigProperties(
593
+ model_name="test_model",
594
+ model_provider_name="openai",
595
+ prompt_id="simple_prompt_builder",
596
+ structured_output_mode="json_schema",
597
+ tools_config=tools_config,
598
+ ),
599
+ )
600
+
601
+ # Create mock tools with duplicate names
602
+ async def mock_name1():
603
+ return "duplicate_name"
604
+
605
+ async def mock_name2():
606
+ return "duplicate_name"
607
+
608
+ mock_tool1 = MagicMock(spec=KilnToolInterface)
609
+ mock_tool1.name = mock_name1
610
+ mock_tool2 = MagicMock(spec=KilnToolInterface)
611
+ mock_tool2.name = mock_name2 # Same name as tool1
612
+
613
+ # Mock tool_from_id to return our mock tools with duplicate names
614
+ with patch(
615
+ "kiln_ai.adapters.model_adapters.base_adapter.tool_from_id"
616
+ ) as mock_tool_from_id:
617
+ mock_tool_from_id.side_effect = [mock_tool1, mock_tool2]
618
+
619
+ # Should raise ValueError when tools have duplicate names
620
+ with pytest.raises(ValueError, match="Each tool must have a unique name"):
621
+ await adapter.available_tools()