krons 0.1.1__py3-none-any.whl → 0.2.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.
Files changed (142) hide show
  1. krons/__init__.py +49 -0
  2. krons/agent/__init__.py +144 -0
  3. krons/agent/mcps/__init__.py +14 -0
  4. krons/agent/mcps/loader.py +287 -0
  5. krons/agent/mcps/wrapper.py +799 -0
  6. krons/agent/message/__init__.py +20 -0
  7. krons/agent/message/action.py +69 -0
  8. krons/agent/message/assistant.py +52 -0
  9. krons/agent/message/common.py +49 -0
  10. krons/agent/message/instruction.py +130 -0
  11. krons/agent/message/prepare_msg.py +187 -0
  12. krons/agent/message/role.py +53 -0
  13. krons/agent/message/system.py +53 -0
  14. krons/agent/operations/__init__.py +82 -0
  15. krons/agent/operations/act.py +100 -0
  16. krons/agent/operations/generate.py +145 -0
  17. krons/agent/operations/llm_reparse.py +89 -0
  18. krons/agent/operations/operate.py +247 -0
  19. krons/agent/operations/parse.py +243 -0
  20. krons/agent/operations/react.py +286 -0
  21. krons/agent/operations/specs.py +235 -0
  22. krons/agent/operations/structure.py +151 -0
  23. krons/agent/operations/utils.py +79 -0
  24. krons/agent/providers/__init__.py +17 -0
  25. krons/agent/providers/anthropic_messages.py +146 -0
  26. krons/agent/providers/claude_code.py +276 -0
  27. krons/agent/providers/gemini.py +268 -0
  28. krons/agent/providers/match.py +75 -0
  29. krons/agent/providers/oai_chat.py +174 -0
  30. krons/agent/third_party/__init__.py +2 -0
  31. krons/agent/third_party/anthropic_models.py +154 -0
  32. krons/agent/third_party/claude_code.py +682 -0
  33. krons/agent/third_party/gemini_models.py +508 -0
  34. krons/agent/third_party/openai_models.py +295 -0
  35. krons/agent/tool.py +291 -0
  36. krons/core/__init__.py +56 -74
  37. krons/core/base/__init__.py +121 -0
  38. krons/core/{broadcaster.py → base/broadcaster.py} +7 -3
  39. krons/core/{element.py → base/element.py} +13 -5
  40. krons/core/{event.py → base/event.py} +39 -6
  41. krons/core/{eventbus.py → base/eventbus.py} +3 -1
  42. krons/core/{flow.py → base/flow.py} +11 -4
  43. krons/core/{graph.py → base/graph.py} +24 -8
  44. krons/core/{node.py → base/node.py} +44 -19
  45. krons/core/{pile.py → base/pile.py} +22 -8
  46. krons/core/{processor.py → base/processor.py} +21 -7
  47. krons/core/{progression.py → base/progression.py} +3 -1
  48. krons/{specs → core/specs}/__init__.py +0 -5
  49. krons/{specs → core/specs}/adapters/dataclass_field.py +16 -8
  50. krons/{specs → core/specs}/adapters/pydantic_adapter.py +11 -5
  51. krons/{specs → core/specs}/adapters/sql_ddl.py +14 -8
  52. krons/{specs → core/specs}/catalog/__init__.py +2 -2
  53. krons/{specs → core/specs}/catalog/_audit.py +2 -2
  54. krons/{specs → core/specs}/catalog/_common.py +2 -2
  55. krons/{specs → core/specs}/catalog/_content.py +4 -4
  56. krons/{specs → core/specs}/catalog/_enforcement.py +3 -3
  57. krons/{specs → core/specs}/factory.py +5 -5
  58. krons/{specs → core/specs}/operable.py +8 -2
  59. krons/{specs → core/specs}/protocol.py +4 -2
  60. krons/{specs → core/specs}/spec.py +23 -11
  61. krons/{types → core/types}/base.py +4 -2
  62. krons/{types → core/types}/db_types.py +2 -2
  63. krons/errors.py +13 -13
  64. krons/protocols.py +9 -4
  65. krons/resource/__init__.py +89 -0
  66. krons/{services → resource}/backend.py +48 -22
  67. krons/{services → resource}/endpoint.py +28 -14
  68. krons/{services → resource}/hook.py +20 -7
  69. krons/{services → resource}/imodel.py +46 -28
  70. krons/{services → resource}/registry.py +26 -24
  71. krons/{services → resource}/utilities/rate_limited_executor.py +7 -3
  72. krons/{services → resource}/utilities/rate_limiter.py +3 -1
  73. krons/{services → resource}/utilities/resilience.py +15 -5
  74. krons/resource/utilities/token_calculator.py +185 -0
  75. krons/session/__init__.py +12 -17
  76. krons/session/constraints.py +70 -0
  77. krons/session/exchange.py +11 -3
  78. krons/session/message.py +3 -1
  79. krons/session/registry.py +35 -0
  80. krons/session/session.py +165 -174
  81. krons/utils/__init__.py +45 -0
  82. krons/utils/_function_arg_parser.py +99 -0
  83. krons/utils/_pythonic_function_call.py +249 -0
  84. krons/utils/_to_list.py +9 -3
  85. krons/utils/_utils.py +6 -2
  86. krons/utils/concurrency/_async_call.py +4 -2
  87. krons/utils/concurrency/_errors.py +3 -1
  88. krons/utils/concurrency/_patterns.py +3 -1
  89. krons/utils/concurrency/_resource_tracker.py +6 -2
  90. krons/utils/display.py +257 -0
  91. krons/utils/fuzzy/__init__.py +6 -1
  92. krons/utils/fuzzy/_fuzzy_match.py +14 -8
  93. krons/utils/fuzzy/_string_similarity.py +3 -1
  94. krons/utils/fuzzy/_to_dict.py +3 -1
  95. krons/utils/schemas/__init__.py +26 -0
  96. krons/utils/schemas/_breakdown_pydantic_annotation.py +131 -0
  97. krons/utils/schemas/_formatter.py +72 -0
  98. krons/utils/schemas/_minimal_yaml.py +151 -0
  99. krons/utils/schemas/_typescript.py +153 -0
  100. krons/utils/validators/__init__.py +3 -0
  101. krons/utils/validators/_validate_image_url.py +56 -0
  102. krons/work/__init__.py +126 -0
  103. krons/work/engine.py +333 -0
  104. krons/work/form.py +305 -0
  105. krons/{operations → work/operations}/__init__.py +7 -4
  106. krons/{operations → work/operations}/builder.py +1 -1
  107. krons/{enforcement → work/operations}/context.py +36 -5
  108. krons/{operations → work/operations}/flow.py +13 -5
  109. krons/{operations → work/operations}/node.py +45 -43
  110. krons/work/operations/registry.py +103 -0
  111. krons/{specs → work}/phrase.py +130 -13
  112. krons/{enforcement → work}/policy.py +3 -3
  113. krons/work/report.py +268 -0
  114. krons/work/rules/__init__.py +47 -0
  115. krons/{enforcement → work/rules}/common/boolean.py +3 -1
  116. krons/{enforcement → work/rules}/common/choice.py +9 -3
  117. krons/{enforcement → work/rules}/common/number.py +3 -1
  118. krons/{enforcement → work/rules}/common/string.py +9 -3
  119. krons/{enforcement → work/rules}/rule.py +1 -1
  120. krons/{enforcement → work/rules}/validator.py +20 -5
  121. krons/{enforcement → work}/service.py +16 -7
  122. krons/work/worker.py +266 -0
  123. {krons-0.1.1.dist-info → krons-0.2.0.dist-info}/METADATA +15 -1
  124. krons-0.2.0.dist-info/RECORD +154 -0
  125. krons/enforcement/__init__.py +0 -57
  126. krons/operations/registry.py +0 -92
  127. krons/services/__init__.py +0 -81
  128. krons-0.1.1.dist-info/RECORD +0 -101
  129. /krons/{specs → core/specs}/adapters/__init__.py +0 -0
  130. /krons/{specs → core/specs}/adapters/_utils.py +0 -0
  131. /krons/{specs → core/specs}/adapters/factory.py +0 -0
  132. /krons/{types → core/types}/__init__.py +0 -0
  133. /krons/{types → core/types}/_sentinel.py +0 -0
  134. /krons/{types → core/types}/identity.py +0 -0
  135. /krons/{services → resource}/utilities/__init__.py +0 -0
  136. /krons/{services → resource}/utilities/header_factory.py +0 -0
  137. /krons/{enforcement → work/rules}/common/__init__.py +0 -0
  138. /krons/{enforcement → work/rules}/common/mapping.py +0 -0
  139. /krons/{enforcement → work/rules}/common/model.py +0 -0
  140. /krons/{enforcement → work/rules}/registry.py +0 -0
  141. {krons-0.1.1.dist-info → krons-0.2.0.dist-info}/WHEEL +0 -0
  142. {krons-0.1.1.dist-info → krons-0.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -15,8 +15,7 @@ from uuid import UUID
15
15
 
16
16
  from pydantic import BaseModel, field_serializer, field_validator
17
17
 
18
- from krons.protocols import Deserializable, Serializable, implements
19
- from krons.types import (
18
+ from krons.core.types import (
20
19
  ModelConfig,
21
20
  Params,
22
21
  Unset,
@@ -25,7 +24,8 @@ from krons.types import (
25
24
  is_unset,
26
25
  not_sentinel,
27
26
  )
28
- from krons.types.db_types import VectorMeta, extract_kron_db_meta
27
+ from krons.core.types.db_types import VectorMeta, extract_kron_db_meta
28
+ from krons.protocols import Deserializable, Serializable, implements
29
29
  from krons.utils import compute_hash, json_dump, now_utc
30
30
 
31
31
  from .element import Element
@@ -56,9 +56,13 @@ def _enable_embedding_requires_dim(config: NodeConfig) -> None:
56
56
  """Validate: embedding_enabled requires positive embedding_dim."""
57
57
  if config.embedding_enabled:
58
58
  if config.is_sentinel_field("embedding_dim"):
59
- raise ValueError("embedding_dim must be specified when embedding is enabled")
59
+ raise ValueError(
60
+ "embedding_dim must be specified when embedding is enabled"
61
+ )
60
62
  if config.embedding_dim <= 0:
61
- raise ValueError(f"embedding_dim must be positive, got {config.embedding_dim}")
63
+ raise ValueError(
64
+ f"embedding_dim must be positive, got {config.embedding_dim}"
65
+ )
62
66
 
63
67
 
64
68
  def _only_typed_content_can_flatten(config: NodeConfig) -> None:
@@ -231,7 +235,9 @@ class Node(Element):
231
235
  cls._resolved_content_type = None
232
236
  else:
233
237
  cls._resolved_content_type = (
234
- None if config.is_sentinel_field("content_type") else config.content_type
238
+ None
239
+ if config.is_sentinel_field("content_type")
240
+ else config.content_type
235
241
  )
236
242
 
237
243
  @field_serializer("content")
@@ -263,7 +269,10 @@ class Node(Element):
263
269
  metadata = value.get("metadata", {})
264
270
  kron_class = metadata.get("kron_class")
265
271
  if kron_class:
266
- if kron_class in NODE_REGISTRY or kron_class.split(".")[-1] in NODE_REGISTRY:
272
+ if (
273
+ kron_class in NODE_REGISTRY
274
+ or kron_class.split(".")[-1] in NODE_REGISTRY
275
+ ):
267
276
  return Node.from_dict(value)
268
277
  return Element.from_dict(value)
269
278
  return value
@@ -271,7 +280,9 @@ class Node(Element):
271
280
  def to_dict(
272
281
  self,
273
282
  mode: Literal["python", "json", "db"] = "python",
274
- created_at_format: (Literal["datetime", "isoformat", "timestamp"] | UnsetType) = Unset,
283
+ created_at_format: (
284
+ Literal["datetime", "isoformat", "timestamp"] | UnsetType
285
+ ) = Unset,
275
286
  meta_key: str | UnsetType = Unset,
276
287
  content_serializer: Callable[[Any], Any] | None = None,
277
288
  **kwargs: Any,
@@ -421,14 +432,18 @@ class Node(Element):
421
432
  and issubclass(content_type, BaseModel)
422
433
  ):
423
434
  content_field_names = set(content_type.model_fields.keys())
424
- content_data = {k: v for k, v in data.items() if k in content_field_names}
435
+ content_data = {
436
+ k: v for k, v in data.items() if k in content_field_names
437
+ }
425
438
  for k in content_field_names:
426
439
  data.pop(k, None)
427
440
  data["content"] = content_type(**content_data)
428
441
 
429
442
  # Handle meta_key for DB rows
430
443
  effective_meta_key = (
431
- meta_key if not is_unset(meta_key) else (config.meta_key if from_row else Unset)
444
+ meta_key
445
+ if not is_unset(meta_key)
446
+ else (config.meta_key if from_row else Unset)
432
447
  )
433
448
 
434
449
  if content_deserializer is not None:
@@ -704,8 +719,8 @@ def create_node(
704
719
  >>> Job = create_node("Job", embedding_enabled=True, embedding_dim=1536)
705
720
 
706
721
  """
707
- from krons.specs.catalog import AuditSpecs, ContentSpecs
708
- from krons.specs.operable import Operable
722
+ from krons.core.specs.catalog import AuditSpecs, ContentSpecs
723
+ from krons.core.specs.operable import Operable
709
724
 
710
725
  # Resolve embedding dimension
711
726
  resolved_embedding_dim: int | UnsetType = Unset
@@ -723,7 +738,9 @@ def create_node(
723
738
  )
724
739
  elif embedding_enabled:
725
740
  if embedding_dim is None or embedding_dim <= 0:
726
- raise ValueError("embedding_dim must be positive when embedding_enabled=True")
741
+ raise ValueError(
742
+ "embedding_dim must be positive when embedding_enabled=True"
743
+ )
727
744
  resolved_embedding_dim = embedding_dim
728
745
  has_embedding = True
729
746
 
@@ -742,7 +759,11 @@ def create_node(
742
759
  include.append("embedding")
743
760
 
744
761
  needs_update_tracking = (
745
- track_updated_at or content_hashing or integrity_hashing or soft_delete or versioning
762
+ track_updated_at
763
+ or content_hashing
764
+ or integrity_hashing
765
+ or soft_delete
766
+ or versioning
746
767
  )
747
768
  if needs_update_tracking:
748
769
  include.append("updated_at")
@@ -805,7 +826,9 @@ def _extract_base_type(annotation: Any) -> Any:
805
826
  if annotation is None:
806
827
  return None
807
828
 
808
- if isinstance(annotation, types.UnionType) or get_origin(annotation) is type(int | str):
829
+ if isinstance(annotation, types.UnionType) or get_origin(annotation) is type(
830
+ int | str
831
+ ):
809
832
  args = get_args(annotation)
810
833
  non_none_args = [a for a in args if a is not type(None)]
811
834
  if non_none_args:
@@ -835,12 +858,14 @@ def generate_ddl(
835
858
  ValueError: If node_cls has no table_name configured
836
859
 
837
860
  """
838
- from krons.specs.catalog import AuditSpecs, ContentSpecs
839
- from krons.specs.operable import Operable
861
+ from krons.core.specs.catalog import AuditSpecs, ContentSpecs
862
+ from krons.core.specs.operable import Operable
840
863
 
841
864
  config = node_cls.get_config()
842
865
  if not config.is_persisted:
843
- raise ValueError(f"{node_cls.__name__} is not persistable (no table_name configured)")
866
+ raise ValueError(
867
+ f"{node_cls.__name__} is not persistable (no table_name configured)"
868
+ )
844
869
 
845
870
  # 1. Build all possible specs for this node
846
871
  content_type = (
@@ -855,7 +880,7 @@ def generate_ddl(
855
880
 
856
881
  # Flatten content: extract fields from BaseModel instead of generic JSONB
857
882
  if config.flatten_content and content_type is not None:
858
- from krons.specs.adapters.pydantic_adapter import PydanticSpecAdapter
883
+ from krons.core.specs.adapters.pydantic_adapter import PydanticSpecAdapter
859
884
 
860
885
  if isinstance(content_type, type) and issubclass(content_type, BaseModel):
861
886
  all_specs.extend(PydanticSpecAdapter.extract_specs(content_type))
@@ -12,9 +12,9 @@ from uuid import UUID
12
12
  from pydantic import Field, PrivateAttr, field_serializer, field_validator
13
13
  from typing_extensions import override
14
14
 
15
+ from krons.core.types import Unset, UnsetType, is_unset
15
16
  from krons.errors import ExistsError, NotFoundError
16
17
  from krons.protocols import Containable, Deserializable, Serializable, implements
17
- from krons.types import Unset, UnsetType, is_unset
18
18
  from krons.utils import extract_types, load_type_from_string, synchronized
19
19
  from krons.utils.concurrency import Lock as AsyncLock
20
20
 
@@ -59,7 +59,9 @@ class Pile(Element, Generic[T]):
59
59
  @property
60
60
  def progression(self) -> Progression:
61
61
  """Read-only copy of progression order."""
62
- return Progression(order=list(self._progression.order), name=self._progression.name)
62
+ return Progression(
63
+ order=list(self._progression.order), name=self._progression.name
64
+ )
63
65
 
64
66
  item_type: set[type] | None = Field(
65
67
  default=None,
@@ -104,7 +106,9 @@ class Pile(Element, Generic[T]):
104
106
  NotFoundError: If order contains UUID not in items
105
107
  TypeError: If item type validation fails
106
108
  """
107
- super().__init__(**{"item_type": item_type, "strict_type": strict_type, **kwargs})
109
+ super().__init__(
110
+ **{"item_type": item_type, "strict_type": strict_type, **kwargs}
111
+ )
108
112
 
109
113
  if items:
110
114
  for item in items:
@@ -128,10 +132,14 @@ class Pile(Element, Generic[T]):
128
132
  def to_dict(
129
133
  self,
130
134
  mode: Literal["python", "json", "db"] = "python",
131
- created_at_format: (Literal["datetime", "isoformat", "timestamp"] | UnsetType) = Unset,
135
+ created_at_format: (
136
+ Literal["datetime", "isoformat", "timestamp"] | UnsetType
137
+ ) = Unset,
132
138
  meta_key: str | UnsetType = Unset,
133
139
  item_meta_key: str | UnsetType = Unset,
134
- item_created_at_format: (Literal["datetime", "isoformat", "timestamp"] | UnsetType) = Unset,
140
+ item_created_at_format: (
141
+ Literal["datetime", "isoformat", "timestamp"] | UnsetType
142
+ ) = Unset,
135
143
  **kwargs: Any,
136
144
  ) -> dict[str, Any]:
137
145
  """Serialize pile with items in progression order.
@@ -350,7 +358,9 @@ class Pile(Element, Generic[T]):
350
358
  raise TypeError("Cannot mix int and UUID in list/tuple indexing")
351
359
  items = [self.get(uid) for uid in keys]
352
360
  else:
353
- raise TypeError(f"list/tuple must contain only int or UUID, got {type(first)}")
361
+ raise TypeError(
362
+ f"list/tuple must contain only int or UUID, got {type(first)}"
363
+ )
354
364
 
355
365
  return Pile(
356
366
  items=items,
@@ -530,7 +540,9 @@ class Pile(Element, Generic[T]):
530
540
  and item_type_data
531
541
  and isinstance(item_type_data[0], str)
532
542
  ):
533
- allowed_types = {load_type_from_string(type_str) for type_str in item_type_data}
543
+ allowed_types = {
544
+ load_type_from_string(type_str) for type_str in item_type_data
545
+ }
534
546
  else:
535
547
  allowed_types = extract_types(item_type_data)
536
548
 
@@ -549,7 +561,9 @@ class Pile(Element, Generic[T]):
549
561
  "(strict_type=True)"
550
562
  )
551
563
  else:
552
- if not any(issubclass(item_type_actual, t) for t in allowed_types):
564
+ if not any(
565
+ issubclass(item_type_actual, t) for t in allowed_types
566
+ ):
553
567
  raise TypeError(
554
568
  f"Item type {kron_class} is not a subclass of any allowed type {allowed_types}"
555
569
  )
@@ -77,13 +77,19 @@ class Processor:
77
77
  if queue_capacity < 1:
78
78
  raise ValueError("Queue capacity must be greater than 0.")
79
79
  if queue_capacity > 10000:
80
- raise ValueError("Queue capacity must be <= 10000 (prevent unbounded batches).")
80
+ raise ValueError(
81
+ "Queue capacity must be <= 10000 (prevent unbounded batches)."
82
+ )
81
83
 
82
84
  # Validate capacity_refresh_time (prevent hot loop or starvation)
83
85
  if capacity_refresh_time < 0.01:
84
- raise ValueError("Capacity refresh time must be >= 0.01s (prevent CPU hot loop).")
86
+ raise ValueError(
87
+ "Capacity refresh time must be >= 0.01s (prevent CPU hot loop)."
88
+ )
85
89
  if capacity_refresh_time > 3600:
86
- raise ValueError("Capacity refresh time must be <= 3600s (prevent starvation).")
90
+ raise ValueError(
91
+ "Capacity refresh time must be <= 3600s (prevent starvation)."
92
+ )
87
93
 
88
94
  # Validate concurrency_limit
89
95
  if concurrency_limit < 1:
@@ -105,7 +111,9 @@ class Processor:
105
111
  self.concurrency_limit = concurrency_limit
106
112
 
107
113
  # Priority queue: (priority, event_uuid) tuples, min-heap ordering
108
- self.queue: concurrency.PriorityQueue[tuple[float, UUID]] = concurrency.PriorityQueue()
114
+ self.queue: concurrency.PriorityQueue[tuple[float, UUID]] = (
115
+ concurrency.PriorityQueue()
116
+ )
109
117
 
110
118
  self._available_capacity = queue_capacity
111
119
  self._execution_mode = False
@@ -231,7 +239,9 @@ class Processor:
231
239
  self._denial_counts.pop(event_id, None)
232
240
 
233
241
  if self.executor:
234
- await self.executor._update_progression(next_event, EventStatus.PROCESSING)
242
+ await self.executor._update_progression(
243
+ next_event, EventStatus.PROCESSING
244
+ )
235
245
 
236
246
  if next_event.streaming:
237
247
 
@@ -255,7 +265,9 @@ class Processor:
255
265
  if self.executor:
256
266
  await self.executor._update_progression(event)
257
267
 
258
- tg.start_soon(self._with_semaphore, invoke_and_update(next_event))
268
+ tg.start_soon(
269
+ self._with_semaphore, invoke_and_update(next_event)
270
+ )
259
271
 
260
272
  events_processed += 1
261
273
  self._available_capacity -= 1
@@ -270,7 +282,9 @@ class Processor:
270
282
 
271
283
  if denial_count >= 3:
272
284
  if self.executor:
273
- await self.executor._update_progression(next_event, EventStatus.ABORTED)
285
+ await self.executor._update_progression(
286
+ next_event, EventStatus.ABORTED
287
+ )
274
288
  self._denial_counts.pop(event_id, None)
275
289
  else:
276
290
  backoff = denial_count * 1.0
@@ -177,7 +177,9 @@ class Progression(Element):
177
177
  """Set item(s) at index. Slice assignment requires list value."""
178
178
  if isinstance(index, slice):
179
179
  if not isinstance(value, list):
180
- raise TypeError(f"Cannot assign {type(value).__name__} to slice, expected list")
180
+ raise TypeError(
181
+ f"Cannot assign {type(value).__name__} to slice, expected list"
182
+ )
181
183
  new_uids = [self._coerce_id(v) for v in value]
182
184
  self.order[index] = new_uids
183
185
  self._rebuild_members()
@@ -4,7 +4,6 @@
4
4
  from .adapters.factory import AdapterType, get_adapter
5
5
  from .catalog import AuditSpecs, CommonSpecs, ContentSpecs
6
6
  from .operable import Operable
7
- from .phrase import CrudOperation, CrudPattern, Phrase, phrase
8
7
  from .protocol import SpecAdapter
9
8
  from .spec import CommonMeta, Spec
10
9
 
@@ -14,12 +13,8 @@ __all__ = (
14
13
  "CommonMeta",
15
14
  "CommonSpecs",
16
15
  "ContentSpecs",
17
- "CrudOperation",
18
- "CrudPattern",
19
16
  "Operable",
20
- "Phrase",
21
17
  "Spec",
22
18
  "SpecAdapter",
23
19
  "get_adapter",
24
- "phrase",
25
20
  )
@@ -17,14 +17,14 @@ from dataclasses import field as dc_field
17
17
  from dataclasses import fields
18
18
  from typing import TYPE_CHECKING, Any
19
19
 
20
- from krons.types._sentinel import Unset, UnsetType, is_sentinel
20
+ from krons.core.types._sentinel import Unset, UnsetType, is_sentinel
21
21
 
22
22
  from ..protocol import SpecAdapter
23
23
  from ..spec import Spec
24
24
  from ._utils import resolve_annotation_to_base_types
25
25
 
26
26
  if TYPE_CHECKING:
27
- from krons.types.base import DataClass, ModelConfig, Params
27
+ from krons.core.types.base import DataClass, ModelConfig, Params
28
28
 
29
29
  from ..operable import Operable
30
30
 
@@ -71,7 +71,9 @@ def _make_validator_method(validators: dict[str, list[Any]], is_frozen: bool) ->
71
71
  errors.append(ValueError(f"Validation failed for '{fname}': {e}"))
72
72
 
73
73
  if errors:
74
- raise ExceptionGroup(f"Field validation failed for {type(self).__name__}", errors)
74
+ raise ExceptionGroup(
75
+ f"Field validation failed for {type(self).__name__}", errors
76
+ )
75
77
 
76
78
  return _validate_with_field_validators
77
79
 
@@ -149,7 +151,7 @@ class DataClassSpecAdapter(SpecAdapter[dict[str, Any]]):
149
151
  Returns:
150
152
  Dynamically created dataclass with validators wired in
151
153
  """
152
- from krons.types.base import DataClass, Params
154
+ from krons.core.types.base import DataClass, Params
153
155
 
154
156
  use_specs = op.get_specs(include=include, exclude=exclude)
155
157
 
@@ -176,7 +178,9 @@ class DataClassSpecAdapter(SpecAdapter[dict[str, Any]]):
176
178
  annotations[field_name] = spec.annotation
177
179
 
178
180
  if "default_factory" in field_kwargs:
179
- class_attrs[field_name] = dc_field(default_factory=field_kwargs["default_factory"])
181
+ class_attrs[field_name] = dc_field(
182
+ default_factory=field_kwargs["default_factory"]
183
+ )
180
184
  elif "default" in field_kwargs:
181
185
  class_attrs[field_name] = field_kwargs["default"]
182
186
 
@@ -221,15 +225,19 @@ class DataClassSpecAdapter(SpecAdapter[dict[str, Any]]):
221
225
  return instance.to_dict()
222
226
 
223
227
  @classmethod
224
- def extract_specs(cls, structure: type[Params] | type[DataClass]) -> tuple[Spec, ...]:
228
+ def extract_specs(
229
+ cls, structure: type[Params] | type[DataClass]
230
+ ) -> tuple[Spec, ...]:
225
231
  """Extract Specs from DataClass/Params, preserving defaults and type modifiers.
226
232
 
227
233
  Raises:
228
234
  TypeError: If structure is not a DataClass or Params subclass
229
235
  """
230
- from krons.types.base import DataClass, Params
236
+ from krons.core.types.base import DataClass, Params
231
237
 
232
- if not isinstance(structure, type) or not issubclass(structure, (DataClass, Params)):
238
+ if not isinstance(structure, type) or not issubclass(
239
+ structure, (DataClass, Params)
240
+ ):
233
241
  raise TypeError(
234
242
  f"structure must be a DataClass or Params subclass, got {type(structure)}"
235
243
  )
@@ -20,15 +20,21 @@ from pydantic.fields import FieldInfo
20
20
  from pydantic_core import PydanticUndefined
21
21
  from pydantic_core._pydantic_core import PydanticUndefinedType
22
22
 
23
- from krons.specs.protocol import SpecAdapter
24
- from krons.specs.spec import Spec
25
- from krons.types._sentinel import Unset, UnsetType, is_sentinel, is_unset, not_sentinel
26
- from krons.types.db_types import FKMeta, VectorMeta
23
+ from krons.core.specs.protocol import SpecAdapter
24
+ from krons.core.specs.spec import Spec
25
+ from krons.core.types._sentinel import (
26
+ Unset,
27
+ UnsetType,
28
+ is_sentinel,
29
+ is_unset,
30
+ not_sentinel,
31
+ )
32
+ from krons.core.types.db_types import FKMeta, VectorMeta
27
33
 
28
34
  from ._utils import resolve_annotation_to_base_types
29
35
 
30
36
  if TYPE_CHECKING:
31
- from krons.specs.operable import Operable
37
+ from krons.core.specs.operable import Operable
32
38
 
33
39
  __all__ = ("PydanticSpecAdapter",)
34
40
 
@@ -27,16 +27,22 @@ from enum import StrEnum
27
27
  from typing import TYPE_CHECKING, Annotated, Any, get_args, get_origin
28
28
  from uuid import UUID
29
29
 
30
- from krons.types._sentinel import Unset, UnsetType, is_sentinel
31
- from krons.types.db_types import FK, FKMeta, Vector, VectorMeta, extract_kron_db_meta
30
+ from krons.core.types._sentinel import Unset, UnsetType, is_sentinel
31
+ from krons.core.types.db_types import (
32
+ FK,
33
+ FKMeta,
34
+ Vector,
35
+ VectorMeta,
36
+ extract_kron_db_meta,
37
+ )
32
38
  from krons.utils.sql import validate_identifier
33
39
 
34
40
  from ..protocol import SpecAdapter
35
41
  from ._utils import resolve_annotation_to_base_types
36
42
 
37
43
  if TYPE_CHECKING:
38
- from krons.specs.operable import Operable
39
- from krons.specs.spec import Spec
44
+ from krons.core.specs.operable import Operable
45
+ from krons.core.specs.spec import Spec
40
46
 
41
47
  __all__ = (
42
48
  # Enums
@@ -414,9 +420,7 @@ class UniqueConstraintSpec:
414
420
  for col in self.columns:
415
421
  validate_identifier(col, "column name")
416
422
  cols = ", ".join(f'"{c}"' for c in self.columns)
417
- return (
418
- f'ALTER TABLE "{schema}"."{table_name}" ADD CONSTRAINT "{self.name}" UNIQUE ({cols});'
419
- )
423
+ return f'ALTER TABLE "{schema}"."{table_name}" ADD CONSTRAINT "{self.name}" UNIQUE ({cols});'
420
424
 
421
425
 
422
426
  @dataclass(frozen=True, slots=True)
@@ -468,7 +472,9 @@ class TableSpec:
468
472
  col_lines = col_separator.join(col_defs)
469
473
 
470
474
  exists_clause = "IF NOT EXISTS " if if_not_exists else ""
471
- return f"CREATE TABLE {exists_clause}{self.qualified_name} (\n {col_lines}\n);"
475
+ return (
476
+ f"CREATE TABLE {exists_clause}{self.qualified_name} (\n {col_lines}\n);"
477
+ )
472
478
 
473
479
  def to_full_ddl(self) -> list[str]:
474
480
  """Generate all DDL statements for this table.
@@ -9,14 +9,14 @@ Pre-defined Specs for common database patterns:
9
9
  - **CommonSpecs**: name, slug, status, email, phone, tenant_id, settings
10
10
 
11
11
  Usage:
12
- from krons.specs.catalog import ContentSpecs, AuditSpecs
12
+ from krons.core.specs.catalog import ContentSpecs, AuditSpecs
13
13
 
14
14
  content_specs = ContentSpecs.get_specs(dim=1536)
15
15
  audit_specs = AuditSpecs.get_specs(use_uuid=True)
16
16
  all_specs = content_specs + audit_specs
17
17
 
18
18
  For custom Specs, use the factories directly:
19
- from krons.specs.factory import create_embedding_spec, create_content_spec
19
+ from krons.core.specs.factory import create_embedding_spec, create_content_spec
20
20
 
21
21
  my_embedding = create_embedding_spec("embedding", dim=1536)
22
22
  my_content = create_content_spec("payload", content_type=MyModel)
@@ -10,8 +10,8 @@ from uuid import UUID
10
10
 
11
11
  from pydantic import BaseModel, Field
12
12
 
13
- from krons.specs.operable import Operable
14
- from krons.specs.spec import Spec
13
+ from krons.core.specs.operable import Operable
14
+ from krons.core.specs.spec import Spec
15
15
  from krons.utils import now_utc
16
16
 
17
17
 
@@ -10,8 +10,8 @@ from uuid import UUID
10
10
 
11
11
  from pydantic import BaseModel
12
12
 
13
- from krons.specs.operable import Operable
14
- from krons.specs.spec import Spec
13
+ from krons.core.specs.operable import Operable
14
+ from krons.core.specs.spec import Spec
15
15
 
16
16
 
17
17
  class CommonSpecs(BaseModel):
@@ -11,10 +11,10 @@ from uuid import UUID, uuid4
11
11
 
12
12
  from pydantic import BaseModel, Field
13
13
 
14
- from krons.specs.operable import Operable
15
- from krons.specs.spec import Spec
16
- from krons.types._sentinel import Unset, UnsetType
17
- from krons.types.db_types import VectorMeta
14
+ from krons.core.specs.operable import Operable
15
+ from krons.core.specs.spec import Spec
16
+ from krons.core.types._sentinel import Unset, UnsetType
17
+ from krons.core.types.db_types import VectorMeta
18
18
  from krons.utils import now_utc
19
19
 
20
20
 
@@ -10,9 +10,9 @@ from typing import Any
10
10
 
11
11
  from pydantic import BaseModel, Field, field_validator
12
12
 
13
- from krons.specs.operable import Operable
14
- from krons.specs.spec import Spec
15
- from krons.types.base import Enum
13
+ from krons.core.specs.operable import Operable
14
+ from krons.core.specs.spec import Spec
15
+ from krons.core.types.base import Enum
16
16
  from krons.utils import now_utc
17
17
 
18
18
  __all__ = (
@@ -8,10 +8,10 @@ from __future__ import annotations
8
8
  from datetime import datetime
9
9
  from uuid import UUID, uuid4
10
10
 
11
- from krons.specs.spec import Spec, not_sentinel
12
- from krons.types import UnsetType
13
- from krons.types._sentinel import Unset
14
- from krons.types.base import is_sentinel
11
+ from krons.core.specs.spec import Spec, not_sentinel
12
+ from krons.core.types import UnsetType
13
+ from krons.core.types._sentinel import Unset
14
+ from krons.core.types.base import is_sentinel
15
15
 
16
16
 
17
17
  def create_datetime_spec(name: str, *, use_default: bool) -> Spec:
@@ -74,7 +74,7 @@ def create_embedding_spec(
74
74
  return Spec(list[float], name=name, default_factory=list)
75
75
  return Spec(list[float], name=name)
76
76
 
77
- from krons.specs.adapters.sql_ddl import Vector
77
+ from krons.core.specs.adapters.sql_ddl import Vector
78
78
 
79
79
  return Spec(Vector[dim], name=name)
80
80
 
@@ -6,8 +6,14 @@ from __future__ import annotations
6
6
  from dataclasses import dataclass
7
7
  from typing import TYPE_CHECKING, Any, Self
8
8
 
9
+ from krons.core.types._sentinel import (
10
+ MaybeUnset,
11
+ Unset,
12
+ UnsetType,
13
+ is_unset,
14
+ not_sentinel,
15
+ )
9
16
  from krons.protocols import Allowable, Hashable, implements
10
- from krons.types._sentinel import MaybeUnset, Unset, UnsetType, is_unset, not_sentinel
11
17
 
12
18
  from .adapters.factory import AdapterType, get_adapter
13
19
  from .protocol import SpecAdapter
@@ -311,4 +317,4 @@ class Operable:
311
317
  Returns:
312
318
  Dict representation of the instance
313
319
  """
314
- return self.adapter.dump_instance(instance, self)
320
+ return self.adapter.dump_instance(instance)
@@ -24,7 +24,7 @@ from __future__ import annotations
24
24
  from abc import ABC, abstractmethod
25
25
  from typing import TYPE_CHECKING, Any, Generic, TypeVar
26
26
 
27
- from krons.types._sentinel import Unset, UnsetType
27
+ from krons.core.types._sentinel import Unset, UnsetType
28
28
 
29
29
  if TYPE_CHECKING:
30
30
  from .operable import Operable
@@ -126,7 +126,9 @@ class SpecAdapter(ABC, Generic[F]):
126
126
  Raises:
127
127
  NotImplementedError: If adapter doesn't support instance creation
128
128
  """
129
- raise NotImplementedError(f"{cls.__name__} does not support instance validation")
129
+ raise NotImplementedError(
130
+ f"{cls.__name__} does not support instance validation"
131
+ )
130
132
 
131
133
  @classmethod
132
134
  def dump_instance(cls, instance: Any, **kwargs) -> dict[str, Any]: