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
@@ -103,14 +103,18 @@ class StringRule(Rule):
103
103
  ValueError: If not a string or constraints violated
104
104
  """
105
105
  if not isinstance(v, str):
106
- raise ValueError(f"Invalid string value: expected str, got {type(v).__name__}")
106
+ raise ValueError(
107
+ f"Invalid string value: expected str, got {type(v).__name__}"
108
+ )
107
109
 
108
110
  if self.min_length is not None and len(v) < self.min_length:
109
111
  raise ValueError(
110
112
  f"String too short: got {len(v)} characters, minimum {self.min_length}"
111
113
  )
112
114
  if self.max_length is not None and len(v) > self.max_length:
113
- raise ValueError(f"String too long: got {len(v)} characters, maximum {self.max_length}")
115
+ raise ValueError(
116
+ f"String too long: got {len(v)} characters, maximum {self.max_length}"
117
+ )
114
118
 
115
119
  if self._compiled_pattern is not None:
116
120
  if len(v) > self.regex_max_input_length:
@@ -119,7 +123,9 @@ class StringRule(Rule):
119
123
  f"maximum {self.regex_max_input_length}"
120
124
  )
121
125
  if not self._compiled_pattern.match(v):
122
- raise ValueError(f"String does not match required pattern: {self.pattern}")
126
+ raise ValueError(
127
+ f"String does not match required pattern: {self.pattern}"
128
+ )
123
129
 
124
130
  async def perform_fix(self, v: Any, t: type) -> Any:
125
131
  """Attempt to convert value to string and re-validate.
@@ -8,8 +8,8 @@ from dataclasses import dataclass, field
8
8
  from enum import IntEnum, auto
9
9
  from typing import Any
10
10
 
11
+ from krons.core.types import Params
11
12
  from krons.errors import ValidationError
12
- from krons.types import Params
13
13
 
14
14
  __all__ = ("Rule", "RuleParams", "RuleQualifier", "ValidationError")
15
15
 
@@ -7,14 +7,16 @@ from collections import deque
7
7
  from datetime import datetime
8
8
  from typing import TYPE_CHECKING, Any, ClassVar
9
9
 
10
- from krons.types import is_sentinel
10
+ from krons.core.types import is_sentinel, not_sentinel
11
11
  from krons.utils.concurrency import is_coro_func
12
12
 
13
13
  from .registry import RuleRegistry, get_default_registry
14
14
  from .rule import Rule, ValidationError
15
15
 
16
16
  if TYPE_CHECKING:
17
- from krons.specs import Operable, Spec
17
+ from pydantic import BaseModel
18
+
19
+ from krons.core.specs import Operable, Spec
18
20
 
19
21
  __all__ = ("Validator",)
20
22
 
@@ -29,7 +31,9 @@ class Validator:
29
31
  ):
30
32
  self.registry = registry or get_default_registry()
31
33
  max_entries = (
32
- max_log_entries if max_log_entries is not None else self.DEFAULT_MAX_LOG_ENTRIES
34
+ max_log_entries
35
+ if max_log_entries is not None
36
+ else self.DEFAULT_MAX_LOG_ENTRIES
33
37
  )
34
38
  self.validation_log: deque[dict[str, Any]] = deque(
35
39
  maxlen=max_entries if max_entries > 0 else None
@@ -141,7 +145,9 @@ class Validator:
141
145
  raise ValidationError(error_msg)
142
146
  else:
143
147
  try:
144
- value = await rule.invoke(field_name, value, spec.base_type, auto_fix=auto_fix)
148
+ value = await rule.invoke(
149
+ field_name, value, spec.base_type, auto_fix=auto_fix
150
+ )
145
151
  except Exception as e:
146
152
  self.log_validation_error(field_name, value, str(e))
147
153
  raise
@@ -171,14 +177,20 @@ class Validator:
171
177
 
172
178
  return value
173
179
 
174
- async def validate_operable(
180
+ async def validate(
175
181
  self,
176
182
  data: dict[str, Any],
177
183
  operable: Operable,
178
184
  capabilities: set[str] | None = None,
179
185
  auto_fix: bool = True,
180
186
  strict: bool = True,
187
+ structure: type[BaseModel] | None = None,
181
188
  ) -> dict[str, Any]:
189
+ if not_sentinel(capabilities, {"none"}) and not capabilities.issubset(
190
+ operable.allowed()
191
+ ):
192
+ raise ValidationError("Capabilities exceed operable's allowed set")
193
+
182
194
  capabilities = capabilities or operable.allowed()
183
195
  validated: dict[str, Any] = {}
184
196
 
@@ -195,4 +207,7 @@ class Validator:
195
207
  spec, value, auto_fix=auto_fix, strict=strict
196
208
  )
197
209
 
210
+ if structure is not None:
211
+ validated = operable.validate_instance(structure, validated)
212
+
198
213
  return validated
@@ -12,9 +12,9 @@ from typing import Any
12
12
 
13
13
  from pydantic import Field, PrivateAttr
14
14
 
15
- from krons.services import ServiceBackend, ServiceConfig
15
+ from krons.resource import ResourceBackend, ResourceConfig
16
+ from krons.work.operations.context import RequestContext
16
17
 
17
- from .context import RequestContext
18
18
  from .policy import EnforcementLevel, PolicyEngine, PolicyResolver
19
19
 
20
20
  logger = logging.getLogger(__name__)
@@ -28,7 +28,7 @@ __all__ = (
28
28
  )
29
29
 
30
30
 
31
- class KronConfig(ServiceConfig):
31
+ class KronConfig(ResourceConfig):
32
32
  """Configuration for KronService.
33
33
 
34
34
  Attributes:
@@ -135,7 +135,7 @@ def get_action_meta(handler: Callable) -> ActionMeta | None:
135
135
  # =============================================================================
136
136
 
137
137
 
138
- class KronService(ServiceBackend):
138
+ class KronService(ResourceBackend):
139
139
  """Service backend with typed actions.
140
140
 
141
141
  Subclasses implement action handlers with @action decorator.
@@ -168,7 +168,9 @@ class KronService(ServiceBackend):
168
168
  config: KronConfig = Field(default_factory=KronConfig)
169
169
  _policy_engine: PolicyEngine | None = PrivateAttr(default=None)
170
170
  _policy_resolver: PolicyResolver | None = PrivateAttr(default=None)
171
- _action_registry: dict[str, tuple[Callable, ActionMeta]] = PrivateAttr(default_factory=dict)
171
+ _action_registry: dict[str, tuple[Callable, ActionMeta]] = PrivateAttr(
172
+ default_factory=dict
173
+ )
172
174
 
173
175
  def __init__(
174
176
  self,
@@ -193,6 +195,9 @@ class KronService(ServiceBackend):
193
195
  def _register_actions(self) -> None:
194
196
  """Scan for @action decorated methods and register them."""
195
197
  for name in dir(self):
198
+ # Skip dunder attributes to avoid Pydantic deprecation warnings
199
+ if name.startswith("__"):
200
+ continue
196
201
  if name.startswith("_"):
197
202
  method = getattr(self, name, None)
198
203
  if method and callable(method):
@@ -287,7 +292,9 @@ class KronService(ServiceBackend):
287
292
 
288
293
  # Validate options if we have typed options_type
289
294
  if meta._options_type and self.config.operable:
290
- options = self.config.operable.validate_instance(meta._options_type, options)
295
+ options = self.config.operable.validate_instance(
296
+ meta._options_type, options
297
+ )
291
298
 
292
299
  # Execute handler
293
300
  result = await handler(options, ctx)
@@ -349,7 +356,9 @@ class KronService(ServiceBackend):
349
356
 
350
357
  for result in results:
351
358
  if EnforcementLevel.is_blocking(result):
352
- raise PermissionError(f"Policy {result.policy_id} blocked: {result.message}")
359
+ raise PermissionError(
360
+ f"Policy {result.policy_id} blocked: {result.message}"
361
+ )
353
362
 
354
363
  except PermissionError:
355
364
  raise
krons/work/worker.py ADDED
@@ -0,0 +1,266 @@
1
+ # Copyright (c) 2025 - 2026, HaiyangLi <quantocean.li at gmail dot com>
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ """Worker - Declarative workflow definition via decorated methods.
5
+
6
+ A Worker defines workflows through:
7
+ - @work: Typed operations with assignment DSL (inputs -> outputs)
8
+ - @worklink: Conditional edges between work methods
9
+
10
+ Example:
11
+ class FileCoder(Worker):
12
+ @work(assignment="instruction, context -> code", capacity=2)
13
+ async def write_code(self, form_id, **kwargs):
14
+ result = await llm.chat(**kwargs)
15
+ return form_id, result.code
16
+
17
+ @worklink(from_="write_code", to_="execute_code")
18
+ async def write_to_execute(self, from_result):
19
+ form_id, code = from_result
20
+ return {"form_id": form_id, "code": code}
21
+
22
+ engine = WorkerEngine(worker=FileCoder())
23
+ await engine.add_task(form=my_form, task_function="write_code")
24
+ await engine.execute()
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import functools
30
+ from dataclasses import dataclass
31
+ from typing import TYPE_CHECKING, Awaitable, Callable
32
+ from uuid import UUID
33
+
34
+ if TYPE_CHECKING:
35
+ from .form import Form
36
+
37
+ __all__ = (
38
+ "Worker",
39
+ "WorkConfig",
40
+ "WorkLink",
41
+ "work",
42
+ "worklink",
43
+ )
44
+
45
+
46
+ @dataclass
47
+ class WorkConfig:
48
+ """Configuration for a @work decorated method.
49
+
50
+ Attributes:
51
+ assignment: DSL string 'inputs -> outputs' for typed I/O
52
+ form_param_key: Parameter name that receives form ID
53
+ capacity: Max concurrent executions (rate limiting)
54
+ refresh_time: Seconds between capacity resets
55
+ timeout: Max execution time in seconds
56
+ """
57
+
58
+ assignment: str = ""
59
+ form_param_key: str = ""
60
+ capacity: int = 1
61
+ refresh_time: float = 0.1
62
+ timeout: float | None = None
63
+
64
+
65
+ @dataclass
66
+ class WorkLink:
67
+ """Edge definition between work methods.
68
+
69
+ Attributes:
70
+ from_: Source method name
71
+ to_: Target method name
72
+ handler_name: Name of the handler method on the Worker
73
+ """
74
+
75
+ from_: str
76
+ to_: str
77
+ handler_name: str
78
+
79
+
80
+ class Worker:
81
+ """Base class for declarative workflow definition.
82
+
83
+ Subclass and decorate methods with @work and @worklink to define workflows.
84
+ Worker maintains form storage and tracks work method metadata.
85
+
86
+ Attributes:
87
+ name: Worker name (default: class name)
88
+ forms: Dict mapping form IDs to Form instances
89
+ _work_methods: Registry of @work decorated methods
90
+ _work_links: Registry of @worklink edges
91
+ _stopped: Stop flag for execution
92
+
93
+ Example:
94
+ class MyCoder(Worker):
95
+ name = "coder"
96
+
97
+ @work(assignment="task -> plan", capacity=2)
98
+ async def plan(self, task_name, **kwargs):
99
+ ...
100
+ return task_name
101
+
102
+ @work(assignment="plan -> code", form_param_key="task_name")
103
+ async def implement(self, task_name, **kwargs):
104
+ ...
105
+
106
+ @worklink(from_="plan", to_="implement")
107
+ async def plan_to_implement(self, from_result):
108
+ return {"task_name": from_result}
109
+ """
110
+
111
+ name: str = "worker"
112
+
113
+ def __init__(self) -> None:
114
+ """Initialize worker state."""
115
+ # Form storage: form_id -> Form
116
+ self.forms: dict[str | UUID, Form] = {}
117
+
118
+ # Collect @work methods from class
119
+ self._work_methods: dict[str, tuple[Callable, WorkConfig]] = {}
120
+ self._work_links: list[WorkLink] = []
121
+ self._stopped = False
122
+
123
+ self._collect_work_metadata()
124
+
125
+ def _collect_work_metadata(self) -> None:
126
+ """Scan class for @work and @worklink decorated methods."""
127
+ for name in dir(self):
128
+ if name.startswith("_"):
129
+ continue
130
+
131
+ attr = getattr(self, name, None)
132
+ if attr is None:
133
+ continue
134
+
135
+ # Check for @work decorator
136
+ if hasattr(attr, "_work_config"):
137
+ config: WorkConfig = attr._work_config
138
+ self._work_methods[name] = (attr, config)
139
+
140
+ # Check for @worklink decorator
141
+ if hasattr(attr, "_worklink_from") and hasattr(attr, "_worklink_to"):
142
+ link = WorkLink(
143
+ from_=attr._worklink_from,
144
+ to_=attr._worklink_to,
145
+ handler_name=name,
146
+ )
147
+ self._work_links.append(link)
148
+
149
+ def get_links_from(self, method_name: str) -> list[WorkLink]:
150
+ """Get all outgoing links from a method."""
151
+ return [link for link in self._work_links if link.from_ == method_name]
152
+
153
+ def get_links_to(self, method_name: str) -> list[WorkLink]:
154
+ """Get all incoming links to a method."""
155
+ return [link for link in self._work_links if link.to_ == method_name]
156
+
157
+ async def stop(self) -> None:
158
+ """Signal worker to stop processing."""
159
+ self._stopped = True
160
+
161
+ async def start(self) -> None:
162
+ """Clear stop flag to allow processing."""
163
+ self._stopped = False
164
+
165
+ def is_stopped(self) -> bool:
166
+ """Check if worker is stopped."""
167
+ return self._stopped
168
+
169
+ def __repr__(self) -> str:
170
+ methods = list(self._work_methods.keys())
171
+ links = len(self._work_links)
172
+ forms = len(self.forms)
173
+ return f"{self.__class__.__name__}(methods={methods}, links={links}, forms={forms})"
174
+
175
+
176
+ def work(
177
+ assignment: str = "",
178
+ *,
179
+ form_param_key: str = "",
180
+ capacity: int = 1,
181
+ refresh_time: float = 0.1,
182
+ timeout: float | None = None,
183
+ ) -> Callable[[Callable[..., Awaitable]], Callable[..., Awaitable]]:
184
+ """Decorator for typed work methods.
185
+
186
+ Args:
187
+ assignment: DSL string 'inputs -> outputs' defining typed I/O.
188
+ Used for form field binding when form_param_key is set.
189
+ form_param_key: Parameter name that receives form ID.
190
+ If set, the engine will bind form fields to kwargs.
191
+ capacity: Max concurrent executions (for rate limiting).
192
+ refresh_time: Seconds between capacity resets.
193
+ timeout: Max execution time in seconds.
194
+
195
+ Returns:
196
+ Decorator that attaches WorkConfig to the method.
197
+
198
+ Example:
199
+ @work(assignment="context, instruction -> code", form_param_key="form_id")
200
+ async def write_code(self, form_id, **kwargs):
201
+ # kwargs contains context, instruction from form
202
+ result = await llm.chat(**kwargs)
203
+ return form_id, result.code
204
+ """
205
+
206
+ def decorator(func: Callable[..., Awaitable]) -> Callable[..., Awaitable]:
207
+ config = WorkConfig(
208
+ assignment=assignment,
209
+ form_param_key=form_param_key,
210
+ capacity=capacity,
211
+ refresh_time=refresh_time,
212
+ timeout=timeout,
213
+ )
214
+
215
+ @functools.wraps(func)
216
+ async def wrapper(*args, **kwargs):
217
+ return await func(*args, **kwargs)
218
+
219
+ wrapper._work_config = config # type: ignore[attr-defined]
220
+ return wrapper
221
+
222
+ return decorator
223
+
224
+
225
+ def worklink(
226
+ from_: str,
227
+ to_: str,
228
+ ) -> Callable[[Callable[..., Awaitable]], Callable[..., Awaitable]]:
229
+ """Decorator for conditional edges between work methods.
230
+
231
+ The decorated function receives the result from the 'from_' method
232
+ and returns kwargs dict for the 'to_' method. Return None to skip
233
+ the edge (conditional routing).
234
+
235
+ Args:
236
+ from_: Source method name
237
+ to_: Target method name
238
+
239
+ Returns:
240
+ Decorator that attaches WorkLink info to the method.
241
+
242
+ Example:
243
+ @worklink(from_="write_code", to_="execute_code")
244
+ async def write_to_execute(self, from_result):
245
+ form_id, code = from_result
246
+ return {"form_id": form_id, "code": code}
247
+
248
+ @worklink(from_="execute_code", to_="debug_code")
249
+ async def execute_to_debug(self, from_result):
250
+ form_id, error = from_result
251
+ if error is not None: # Conditional edge
252
+ return {"form_id": form_id, "error": error}
253
+ # Return None = edge not taken
254
+ """
255
+
256
+ def decorator(func: Callable[..., Awaitable]) -> Callable[..., Awaitable]:
257
+ @functools.wraps(func)
258
+ async def wrapper(*args, **kwargs):
259
+ return await func(*args, **kwargs)
260
+
261
+ # Store link info - handler_name will be set during _collect_work_metadata
262
+ wrapper._worklink_from = from_ # type: ignore[attr-defined]
263
+ wrapper._worklink_to = to_ # type: ignore[attr-defined]
264
+ return wrapper
265
+
266
+ return decorator
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: krons
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Spec-based composable framework for building type-safe systems
5
5
  Project-URL: Homepage, https://github.com/khive-ai/krons
6
6
  Project-URL: Repository, https://github.com/khive-ai/krons
@@ -22,7 +22,21 @@ Requires-Dist: anyio>=4.10.0
22
22
  Requires-Dist: httpx>=0.26.0
23
23
  Requires-Dist: orjson>=3.10.0
24
24
  Requires-Dist: pydantic>=2.10.0
25
+ Requires-Dist: pyyaml>=6.0.3
25
26
  Requires-Dist: rapidfuzz>=3.10.0
27
+ Provides-Extra: agent
28
+ Requires-Dist: fastmcp>=2.14.4; extra == 'agent'
29
+ Requires-Dist: tiktoken>=0.11.0; extra == 'agent'
30
+ Provides-Extra: all
31
+ Requires-Dist: fastmcp>=2.14.4; extra == 'all'
32
+ Requires-Dist: rich>=13.0; extra == 'all'
33
+ Requires-Dist: tiktoken>=0.11.0; extra == 'all'
34
+ Provides-Extra: display
35
+ Requires-Dist: rich>=13.0; extra == 'display'
36
+ Provides-Extra: fastmcp
37
+ Requires-Dist: fastmcp>=2.14.4; extra == 'fastmcp'
38
+ Provides-Extra: tiktoken
39
+ Requires-Dist: tiktoken>=0.11.0; extra == 'tiktoken'
26
40
  Description-Content-Type: text/markdown
27
41
 
28
42
  # krons
@@ -0,0 +1,154 @@
1
+ krons/__init__.py,sha256=4q7g_NShAZ3SXLVTZ4H8vFSCXpps-3tjCs7qg6WkQPI,1359
2
+ krons/errors.py,sha256=nRWkWZmokOlp3hquC2dBe-gowdVIHllENiD0KxU3m8U,4051
3
+ krons/protocols.py,sha256=xYJUHdXbFHYtjy3rcEt8ttIngzigEve7tYa-8G35v7k,15333
4
+ krons/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ krons/agent/__init__.py,sha256=7AfP-1BHYosM5MiqcSOpoGF0y-bQ2OKN8oQePR2o98Y,4581
6
+ krons/agent/tool.py,sha256=JDlj_QCMw6ILKu2NkKLOoywiIlIIQwVfS-A_HT88OTg,8573
7
+ krons/agent/mcps/__init__.py,sha256=B3RYDI0XaDaECpgxqFp5bBIdCFRGPyzbCDpQeljY0P0,447
8
+ krons/agent/mcps/loader.py,sha256=SAw3ZLvBYHfT1bklLI7i15mnqwAA_aZtnJRR9WEfKl4,10554
9
+ krons/agent/mcps/wrapper.py,sha256=tW4aXzMMBqh4BtcuEaLxYqLxttGRJ06UQSjWmqdsGfI,28169
10
+ krons/agent/message/__init__.py,sha256=vumj0lHyraEoshw0tx8yWt5fyUUuAC3qVBiSLQuq-9A,499
11
+ krons/agent/message/action.py,sha256=ynONthCd78gWzl3dbQughJOGd-Iys6lbOzzYwuLXGWU,2047
12
+ krons/agent/message/assistant.py,sha256=V75490V9mQLKbBkH9cYAmnva2-Q3hwCAj_4flLUCvOE,1459
13
+ krons/agent/message/common.py,sha256=j9rpVoZhH6FV9JLVv6K-IgRJqPGnT5Vcw80UsEWv5ME,1282
14
+ krons/agent/message/instruction.py,sha256=jouxli_yDwRcLJhXs8f9cR0MdreW3pNRDIw2ha7K4uE,4793
15
+ krons/agent/message/prepare_msg.py,sha256=85XB-S2qxzXAUxn0cu46LNbWq0JL6w1IO1soJ3ci0Y4,7017
16
+ krons/agent/message/role.py,sha256=wKY5gIov4yHuvHiXEGFJ8YIaDR2YcmyH83JnDLgnFtI,1397
17
+ krons/agent/message/system.py,sha256=vCwFrYtM8K-5bVvl-mo0xW-Q_1AWqIAOgwDnNQ41DeA,1884
18
+ krons/agent/operations/__init__.py,sha256=UqKGE99xyYBGHnEHPVLq8Bf7dvs195gAnpMH3zpjNNA,2095
19
+ krons/agent/operations/act.py,sha256=WeUiVMcYOQN2EYLEvQU17HcqoQkcWzuqIgJjGP4AWXM,3606
20
+ krons/agent/operations/generate.py,sha256=oNXAwUKw3rcPlGkgq8zhggnNJPVcAzIIUhYIca23Ro0,5447
21
+ krons/agent/operations/llm_reparse.py,sha256=kF_KglZu_R4RVTpl-1lheeHGfvsK1bvAJidDdpW1iEA,2696
22
+ krons/agent/operations/operate.py,sha256=zOIPRoLYV0sXeSTmCvuD5mlwArimP456a7GEpxljjQ8,8966
23
+ krons/agent/operations/parse.py,sha256=HN7gnRm5_6gbabah3enaL280FVywQqIK5N6oOZG8NGQ,8261
24
+ krons/agent/operations/react.py,sha256=f5_5IVf8oi2TD8QXT53DefTxd1zO0nMmJ07SrL_28NQ,9468
25
+ krons/agent/operations/specs.py,sha256=UzH3A8VivQkUZdjDq78T_pmBQlY-BJafOVAKvpS0go8,7407
26
+ krons/agent/operations/structure.py,sha256=8HN5_dA4sYZFUbVPffEGmcamm9VUxFveAko59sgWydI,5250
27
+ krons/agent/operations/utils.py,sha256=goot2IAmrxTOoJa1kn2kfvv03i8mb02ifOKfBJMv_Qw,2335
28
+ krons/agent/providers/__init__.py,sha256=XJtszdh8f5sfAR0eQipKplBSLdKwtL0F7uQPmah8g6s,555
29
+ krons/agent/providers/anthropic_messages.py,sha256=x0oBKQa-T3zu8TyZ50Rm1fvgkY8ukzvAZJc1HVugBh0,4388
30
+ krons/agent/providers/claude_code.py,sha256=nTKJkK1gGUdCgXpzRXiGtC840a5qm0tKBeakqlPQ9Kw,9881
31
+ krons/agent/providers/gemini.py,sha256=TCJkk9iSnnkPdDuTlAB5yOphNYUPkPGKVYkrja9zcuI,9059
32
+ krons/agent/providers/match.py,sha256=3kiW-hyfnF6UgBYD7LG4KFhFKXbWpDdtDQ71-9t5wIQ,2251
33
+ krons/agent/providers/oai_chat.py,sha256=-97XBJ6WQT9OsjKSrV5s3or-WhBfUjDHomGiBYjCeVY,5463
34
+ krons/agent/third_party/__init__.py,sha256=gR454Rk5b1Bv3QibE-822UcoSWhpLCLtJae028QGtN4,110
35
+ krons/agent/third_party/anthropic_models.py,sha256=rd2Skh_Xx1S2G1JXi2YFb1j6SHm62e7brNBq9CZPAgI,3968
36
+ krons/agent/third_party/claude_code.py,sha256=NBYMsdPheb0PqGgTO2_aUAR2XoGDsPUwsB7Nd9PjipA,23758
37
+ krons/agent/third_party/gemini_models.py,sha256=2dag2WbSTKLBd8t0F7t_TXCcl7aqsTFgDI6XLkhsZwM,17416
38
+ krons/agent/third_party/openai_models.py,sha256=L-GkJ-bBW5zwPbgCWEYHMNqRiZfFTAUJE96AVZoDAkQ,8040
39
+ krons/core/__init__.py,sha256=HG0wBaNCbH3xGDRNX3657g-hZo4Isu2MKaXeUXmXqa0,3496
40
+ krons/core/base/__init__.py,sha256=Edl_HH2F1l0SMHMzuEPU_IFjkigRR1vtqVXcPm-mr1o,3614
41
+ krons/core/base/broadcaster.py,sha256=Es__WfL-j2h5NS6aU18fgaFkZsJIL-zDe86Qvlea-io,4013
42
+ krons/core/base/element.py,sha256=LqBbmPttXoDAFy56JzWhSJ4sBw_LW7hMGxZUog85N8g,7642
43
+ krons/core/base/event.py,sha256=iZQ65Xg3a8eaCEl4Hca-pxPNtckhrHkydEqYyppbuo0,11524
44
+ krons/core/base/eventbus.py,sha256=z45ORtGey5A1N9hdyEPOhlX1whaTTdqdk7g3XEDL-_8,3761
45
+ krons/core/base/flow.py,sha256=eqsYm8QO7bD5Y9VYnlpHFWpaUCY0rCeKGrDrFUyBVA4,12364
46
+ krons/core/base/graph.py,sha256=FiTMArxuz6At3oYPEoamES3FtBM-AM6QnA7EQ8G18mo,15972
47
+ krons/core/base/node.py,sha256=0_-R6uNe6-LF3adQRZowSIICdy6ep3cQIQRdF0oosoQ,34699
48
+ krons/core/base/pile.py,sha256=ZKvnX3BjMsrH989TLNZII1dDWv4yPhSRzLKXx2yzyKQ,21108
49
+ krons/core/base/processor.py,sha256=GrdNZa5YD0tXle847ttnxuWe4Ego1MhULzWHmSz5RqQ,18768
50
+ krons/core/base/progression.py,sha256=srcrmp_zALgg7II5TJsuMM9DdNJszgTxLxvES0WBOTE,9844
51
+ krons/core/specs/__init__.py,sha256=AKFEXqLmJpW__Y6xorJ1Vbp7AZ46kIs0157STVFGVWk,500
52
+ krons/core/specs/factory.py,sha256=TsRZIoWuz0sLYUGfQ_X5Gff2oBll-quk-kOnpX5_yB0,3362
53
+ krons/core/specs/operable.py,sha256=zO15i56_UzTTuM3yg_-EMtQY1Equ_WBi3rUCoCKrYck,11067
54
+ krons/core/specs/protocol.py,sha256=Se-Cow7de4hF4vkvw5qYj14c37JJ-4aJSDIvJHFyst8,4392
55
+ krons/core/specs/spec.py,sha256=QaVWN3ZrX8l1x15xXtfpNGzSIV01X0H3jy9Mjv9vT8Y,18706
56
+ krons/core/specs/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ krons/core/specs/adapters/_utils.py,sha256=ChWH-C2LRXaXiWM3n7P0DZ8Oci5dSDq59DIJtHx2h-g,1365
58
+ krons/core/specs/adapters/dataclass_field.py,sha256=thhgC3iQsrkfMkKzB4XmDbwh4fpLYocdL0KvY_zxbzo,8802
59
+ krons/core/specs/adapters/factory.py,sha256=_LoSMCtHNkK5kNL5LUDjHvJJ2BtDHAaW1gly5LpNPXQ,1572
60
+ krons/core/specs/adapters/pydantic_adapter.py,sha256=UxnOtJdeIyJEPBBjSACWE-JVc0yWxHSepz5i2SZhS6A,10410
61
+ krons/core/specs/adapters/sql_ddl.py,sha256=NTttvx16X926qeQNWxqdoLlToeiMwufpKEPWNdAXHg0,31377
62
+ krons/core/specs/catalog/__init__.py,sha256=TwS7hvGxa4-2Usu5rKGlhmUS0hhBlRzVNFNKDE7q8eU,1231
63
+ krons/core/specs/catalog/_audit.py,sha256=g-L4eSJw3H0hfejex5LwsnepaGyTUPrL8JbPU7lPycY,1260
64
+ krons/core/specs/catalog/_common.py,sha256=ItOPWV1fEeaz6ss5XNZYUetp204saIs7s5Bl0Jt8AOQ,1207
65
+ krons/core/specs/catalog/_content.py,sha256=pQAbgjoObZcAQLe8Wg-_sqQ8VYZUGsRQJnjuiCjH-p0,1972
66
+ krons/core/specs/catalog/_enforcement.py,sha256=JlKF_qGc-Xk7E_ebvq6lQs19iRBAWk2TOe1Qm7XMf1k,2126
67
+ krons/core/types/__init__.py,sha256=pJ6kuop7vSLZp5jMBs-CQ7CHRjvUuO8kHhpZ34KM85I,1049
68
+ krons/core/types/_sentinel.py,sha256=QJGyRAYNkJ2ylw6dhxPHJNgmxqBdorBd-xx7pNrUykw,8855
69
+ krons/core/types/base.py,sha256=Un3MrPGuyns9SgPczJ5vbQExemTO-9B2Eks87NDd--A,12330
70
+ krons/core/types/db_types.py,sha256=3ZaAXJe4dartmF-IyKr59NVlL2EbGpx7AtVqqbrIXIk,8136
71
+ krons/core/types/identity.py,sha256=Ccb5oJArC1PEzdzNPlLi_oK87uKx7BFevX9rvY9y-14,1949
72
+ krons/resource/__init__.py,sha256=h83vOSa6zXXMRdfxch7yg7kGy6Pe_6c0wWANByATbZ8,2783
73
+ krons/resource/backend.py,sha256=mW1kkAZrUwnBZeMOY_0I_egpTKpuNyIs5Mps4r2cOxk,10979
74
+ krons/resource/endpoint.py,sha256=X_Yt5KLXKN5Wwc75MX0c5gPyE_Dlv16rIfm8CKd1xYE,22253
75
+ krons/resource/hook.py,sha256=XQujjDwBZa2vCktP6Ey0QFfFFNEd6igc1qUR5-tfeQU,17115
76
+ krons/resource/imodel.py,sha256=_BOfbLk5JNoKAnjf3k67E6O2Qef4fsKa1hprw1C4L1Q,18595
77
+ krons/resource/registry.py,sha256=Vqe8uUtMMtxu4NgU5RUPFmpIxtKxdCfmVQQy1lhZMZo,3829
78
+ krons/resource/utilities/__init__.py,sha256=-ycdoYgtXrliJwbtQGMHBRvZL0qX2xLzooL3RNV99x4,1013
79
+ krons/resource/utilities/header_factory.py,sha256=WZCCZMh9EJVi8tnY7dJD07FcTOrrUMvecJmzy8P65Os,2992
80
+ krons/resource/utilities/rate_limited_executor.py,sha256=xtvxTeHowoghb4WpY_9WNgqbFKHPBZKtKbaGyaTpTsk,9710
81
+ krons/resource/utilities/rate_limiter.py,sha256=DdaqnxOnst43ZAxcC9kBnnFbUCAsR89KzA0XL5xGPtU,6003
82
+ krons/resource/utilities/resilience.py,sha256=eOPSZ6m89IH_RCgaGLrFPQGTZtMBZOrs8G0sjSpfv40,14389
83
+ krons/resource/utilities/token_calculator.py,sha256=gBQvkmqL4gnqFx5o-FtPeoLDPBFTdN0ZpFkaT71VVLk,6437
84
+ krons/session/__init__.py,sha256=aCdCYe2HCLV8ujlBZHSqFr0nF8gj_PypI0BXoIU7ThU,1017
85
+ krons/session/constraints.py,sha256=DvmLKyf5eYUX2nxCDcco1-uDipGjiIJwoUxWVtX2w84,2361
86
+ krons/session/exchange.py,sha256=QChEqK5NFZJpHWxPrXd8LkGBCFg6LNONd1ZEy0MufpI,9165
87
+ krons/session/message.py,sha256=mtZ-PYCCoyWLy7BSB5TL5a0hIt0aQX2zdckOCIl6NZ0,2007
88
+ krons/session/registry.py,sha256=13pPKmDZJaj9q27oUOdtH6-jrHP_HDFF8lCdcNF--EE,999
89
+ krons/session/session.py,sha256=bBK6rYPmYu5YcmU-oWoJL9pU8pdzr9Y4Z5wcIIiuirw,13221
90
+ krons/utils/__init__.py,sha256=V-jTKULdofjJXxcEHygefKV_v6XE4H3poCdxPLjvf_4,1718
91
+ krons/utils/_function_arg_parser.py,sha256=H5JVLBVY8W9ZNkZ4_YVtVVY1rFYvnIRhSrAhKEdj2Qc,3479
92
+ krons/utils/_hash.py,sha256=W2Ma9v8-INPaGkur7GTtbF8KwuXSJNSwk8DCNPRvx8Q,6859
93
+ krons/utils/_json_dump.py,sha256=rpBmr0NCmIKRdmpgn1nSWIHI3FTsGYsQjOa3YTxCi3M,12482
94
+ krons/utils/_lazy_init.py,sha256=bCx_W3dfzirB5KnAt6_jmbnwOk2xbU7-kgOhMQqzW70,1806
95
+ krons/utils/_pythonic_function_call.py,sha256=PAqnb-PNzVBvIrXh5-680mj7BlRiUziiHkjxELe0q78,8388
96
+ krons/utils/_to_list.py,sha256=RuiUWkoxHjD-2pqbbumar69AADCKYoGqSKL5FPu6LdM,6114
97
+ krons/utils/_to_num.py,sha256=NyyIL9Az1EaW6QFh9R7AeJdaUPoSRBNVBX9yj78wpok,3102
98
+ krons/utils/_utils.py,sha256=g1LAKX9-AwREb-XzXaAaHMCeSBlhtfWMu7GK1XDDAzg,11145
99
+ krons/utils/display.py,sha256=haAzWny-Ez1H6LphxNsEaYyFY3uctj2xbvgR8ZAUfJg,7312
100
+ krons/utils/concurrency/__init__.py,sha256=1HD-aY4Hevde0Hm0-VYa0eheT5OiwhlnDJtofIuV9wk,6754
101
+ krons/utils/concurrency/_async_call.py,sha256=cb7iXphip1zKPsim6whf-nCvdopq1spQNqx7sWxiejo,10233
102
+ krons/utils/concurrency/_cancel.py,sha256=b9f6yT8gObS6Y3EWKoGzNfYxqM1ZrN_8ctfyIjT1m1U,3326
103
+ krons/utils/concurrency/_errors.py,sha256=8bG72f71OxWYTdQ9AmUnI20UjEz0UYsWjQayter4CNI,2603
104
+ krons/utils/concurrency/_patterns.py,sha256=Xl31p63JkU370N9bA05uu60GDXrgwm1DHCjEq2U8-oo,11540
105
+ krons/utils/concurrency/_primitives.py,sha256=D1Rl1hujXXPdL4Mw6eW5EN8utM3bh8vmmFtXmuvsDw0,9024
106
+ krons/utils/concurrency/_priority_queue.py,sha256=wGi6ESS6AIZ0QNRBQR5UwcSQI5GhKjATBC_aEw6c0aQ,4342
107
+ krons/utils/concurrency/_resource_tracker.py,sha256=aBLTpSaUsUCtRLEHzIaBYu0NOuACFbIt3JGACo7K-0E,3179
108
+ krons/utils/concurrency/_run_async.py,sha256=A_vuPi9-wWRr3oXiAMnv3l7MV2B76jkBXoVztX_Vcgo,1940
109
+ krons/utils/concurrency/_task.py,sha256=4ivkiUUbutheoYZ-G8-mTfHX4YgWguGIy1v5hSU871w,2528
110
+ krons/utils/concurrency/_utils.py,sha256=CyH_z4prYFeCFgwk4Pc3q0m5NRzDB2TP-G2oxdM_-C0,2136
111
+ krons/utils/fuzzy/__init__.py,sha256=aztwfirLUDf8i-NukKhER1Pp0cZBcgtD92G1n_I4cq4,502
112
+ krons/utils/fuzzy/_extract_json.py,sha256=6Y-QEfXrTBdaNmlbMfVm6xJPBKI0RBbr_t0VYGE7nMo,2922
113
+ krons/utils/fuzzy/_fuzzy_json.py,sha256=hV6v9YkQpGxwOnhpLM6jkrG5fZKYluMTxgdqsk5sTew,9151
114
+ krons/utils/fuzzy/_fuzzy_match.py,sha256=6uDoKwqEnms_NMT2T4GB0LC9hhyeuEOOCAu39vO1COA,4953
115
+ krons/utils/fuzzy/_string_similarity.py,sha256=4G0lgBek8zgRcgKi6V0npwRKdkdmQ_wfayr3eCLZmEY,6155
116
+ krons/utils/fuzzy/_to_dict.py,sha256=cS-7NPKIePFlsGSRExCnBRPn7qHIHmcqR1tQBl5tRjE,12941
117
+ krons/utils/schemas/__init__.py,sha256=Si_UjyztaT0Shi85ISs6ESpTLohk9yLSYdy2x4-82Yo,701
118
+ krons/utils/schemas/_breakdown_pydantic_annotation.py,sha256=wfgrCnpPP74UpDyeOxox4uZgVEJZU7UBiBwZHL0ocT0,4075
119
+ krons/utils/schemas/_formatter.py,sha256=DSxYkJDNncno1T_FSEAa1B3BrONfR_swFbd1AOtrtcg,2682
120
+ krons/utils/schemas/_minimal_yaml.py,sha256=IhbPmInpLpuQpPcTtW1noLoVi4JLFBUL2aRaeLvoB2Q,4652
121
+ krons/utils/schemas/_typescript.py,sha256=XrbUQBbWxhzwuAXS6w54vwBno9Bg3dPpqZFRPPQIKBg,5240
122
+ krons/utils/sql/__init__.py,sha256=yNjm9Dr-ZjrZSD3Lext7fPR80qX5svGT2PnXqlb5qXs,264
123
+ krons/utils/sql/_sql_validation.py,sha256=smxNU3HjPhQuRK5ehG9Fl4DeljKK9tqUQIvRUopgvc8,4229
124
+ krons/utils/validators/__init__.py,sha256=qmCYoL6fQL1O6-GcfcUARii_fjXYNed6rKZWOp3skj8,87
125
+ krons/utils/validators/_validate_image_url.py,sha256=WAffNY3WpPFe_lqFLHumJS0_hm92NwIOmDOK1GR61ew,1858
126
+ krons/work/__init__.py,sha256=L7PoU-Y_RFQCiw8HqC7KSp4KkgyardWbB5mmnNu0cjs,3967
127
+ krons/work/engine.py,sha256=ZHZzzRqedpLEkcX5eQ6zZQMXYfgmLMRN2JOwkLajND4,10924
128
+ krons/work/form.py,sha256=wxfjwCe8JglpeoRcflWquMSSldCCU4kOL26Q_r47GGE,9268
129
+ krons/work/phrase.py,sha256=7PYPcprA_p7_eZx32EzHd6d7Nc2zLjiIyYTJmqwRUNo,18949
130
+ krons/work/policy.py,sha256=3fp8L0R2lxJ6w5YkgWF_0B1gkXyPx1nCjSwu0_3mmcY,2146
131
+ krons/work/report.py,sha256=wxjMGnUc8b2Jn26l0t0k0cWetZFDyvyqBz0ldae4BD0,9027
132
+ krons/work/service.py,sha256=yayqnZHb14rhJoXfj_70Xh0WqdAkgwtTvw7OLzBlCY8,12103
133
+ krons/work/worker.py,sha256=hK7t5ztG_5wKPScwjtsctP4-ob6bHw9WKRJTw_gw_Fc,8494
134
+ krons/work/operations/__init__.py,sha256=vU-jy0Xy25W4vj98wV3sk3c8x6hKc5sf4nW3U_FQGdY,999
135
+ krons/work/operations/builder.py,sha256=_OGvooSl8s3Pmx8En15SX4XxQ12wF2ZszwVb5Hqzdpc,7779
136
+ krons/work/operations/context.py,sha256=rMcKR8kJkVk-7X1nW8LGoSjW4Eaj66LM46El8wwURmU,5323
137
+ krons/work/operations/flow.py,sha256=RL_GIIKlIURsbLp4-xRA7bJukeCVx0b_garodGd1NhI,14803
138
+ krons/work/operations/node.py,sha256=3NbM2o22oMpFXy6I7osGKIOIzJ69r5Bby99LHrNifr4,3374
139
+ krons/work/operations/registry.py,sha256=cVQA36_jgr9bxRiCsVM_plGPrTVr08vci1aio3olZyM,3483
140
+ krons/work/rules/__init__.py,sha256=oxBsYI3vxAp85G1pMIpQM_84HUYwHbB1lxa9t4uB6YY,1187
141
+ krons/work/rules/registry.py,sha256=JFdwcIVtysntj6wMY3bO7-hqwNU7QIoIbEQuhsy5O4U,4742
142
+ krons/work/rules/rule.py,sha256=uKjjiBwgzryiAOyTUI2YiqSyFg3QluvNRJ09EwtrbK8,9471
143
+ krons/work/rules/validator.py,sha256=CbbdueLI_6JvbbG0yvcljyhjO3HhpF4mlfBTzdhP4jA,7240
144
+ krons/work/rules/common/__init__.py,sha256=U0rEcHOxLftR4-xJNuuXMSDYFAvbs0KzwV3GhlZcUrY,1026
145
+ krons/work/rules/common/boolean.py,sha256=zX9i-oggejwFA0QYQSj1rDU1epqqpUe-ARFS4aol3qY,2644
146
+ krons/work/rules/common/choice.py,sha256=QT0qMDvoPHTGjYeybRkZX8oolIy8Y3iQIqehoV28cco,3264
147
+ krons/work/rules/common/mapping.py,sha256=Loq54MNEtwpnHN0aypTjFOqwoOKLEysddHh-JESedvs,3824
148
+ krons/work/rules/common/model.py,sha256=xmM6coEThf_fgIiqJiyDgvdfib_FpVeY6LgWPVcWSwU,3026
149
+ krons/work/rules/common/number.py,sha256=cCukgMSpQu5RdYK5rXAUyop9qXgDRfLCioMvE8kIzHg,3162
150
+ krons/work/rules/common/string.py,sha256=zHp_OLh0FL4PvmSlyDTEzb2I97-DBSEyI2zcMo10voA,5090
151
+ krons-0.2.0.dist-info/METADATA,sha256=BibIkvS6d8-3CoLW3Toj0hCpeQiWdv9PgGmk17CUx3g,2527
152
+ krons-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
153
+ krons-0.2.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
154
+ krons-0.2.0.dist-info/RECORD,,