krons 0.2.0__tar.gz → 0.2.1__tar.gz
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.
- {krons-0.2.0 → krons-0.2.1}/PKG-INFO +1 -1
- {krons-0.2.0 → krons-0.2.1}/pyproject.toml +1 -1
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/__init__.py +0 -11
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/form.py +4 -67
- {krons-0.2.0 → krons-0.2.1}/tests/work/test_form.py +0 -167
- {krons-0.2.0 → krons-0.2.1}/uv.lock +1 -1
- krons-0.2.0/src/krons/work/phrase.py +0 -522
- krons-0.2.0/src/krons/work/policy.py +0 -80
- krons-0.2.0/src/krons/work/service.py +0 -379
- krons-0.2.0/tests/enforcement/test_service.py +0 -591
- krons-0.2.0/tests/specs/test_phrase.py +0 -633
- krons-0.2.0/tests/utils/concurrency/__init__.py +0 -2
- krons-0.2.0/tests/work/test_phrase.py +0 -1141
- {krons-0.2.0 → krons-0.2.1}/.github/workflows/release.yml +0 -0
- {krons-0.2.0 → krons-0.2.1}/.gitignore +0 -0
- {krons-0.2.0 → krons-0.2.1}/.python-version +0 -0
- {krons-0.2.0 → krons-0.2.1}/CLAUDE.md +0 -0
- {krons-0.2.0 → krons-0.2.1}/LICENSE +0 -0
- {krons-0.2.0 → krons-0.2.1}/README.md +0 -0
- {krons-0.2.0 → krons-0.2.1}/cookbooks/007_fan_out_in.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/cookbooks/test_conduct.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/mcps/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/mcps/loader.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/mcps/wrapper.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/message/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/message/action.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/message/assistant.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/message/common.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/message/instruction.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/message/prepare_msg.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/message/role.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/message/system.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/operations/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/operations/act.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/operations/generate.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/operations/llm_reparse.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/operations/operate.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/operations/parse.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/operations/react.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/operations/specs.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/operations/structure.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/operations/utils.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/providers/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/providers/anthropic_messages.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/providers/claude_code.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/providers/gemini.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/providers/match.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/providers/oai_chat.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/third_party/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/third_party/anthropic_models.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/third_party/claude_code.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/third_party/gemini_models.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/third_party/openai_models.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/agent/tool.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/broadcaster.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/element.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/event.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/eventbus.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/flow.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/graph.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/node.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/pile.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/processor.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/base/progression.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/adapters/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/adapters/_utils.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/adapters/dataclass_field.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/adapters/factory.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/adapters/pydantic_adapter.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/adapters/sql_ddl.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/catalog/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/catalog/_audit.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/catalog/_common.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/catalog/_content.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/catalog/_enforcement.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/factory.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/operable.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/protocol.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/specs/spec.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/types/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/types/_sentinel.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/types/base.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/types/db_types.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/core/types/identity.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/errors.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/protocols.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/py.typed +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/backend.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/endpoint.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/hook.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/imodel.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/registry.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/utilities/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/utilities/header_factory.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/utilities/rate_limited_executor.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/utilities/rate_limiter.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/utilities/resilience.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/resource/utilities/token_calculator.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/session/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/session/constraints.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/session/exchange.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/session/message.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/session/registry.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/session/session.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/_function_arg_parser.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/_hash.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/_json_dump.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/_lazy_init.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/_pythonic_function_call.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/_to_list.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/_to_num.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/_utils.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/_async_call.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/_cancel.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/_errors.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/_patterns.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/_primitives.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/_priority_queue.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/_resource_tracker.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/_run_async.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/_task.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/concurrency/_utils.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/display.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/fuzzy/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/fuzzy/_extract_json.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/fuzzy/_fuzzy_json.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/fuzzy/_fuzzy_match.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/fuzzy/_string_similarity.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/fuzzy/_to_dict.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/schemas/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/schemas/_breakdown_pydantic_annotation.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/schemas/_formatter.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/schemas/_minimal_yaml.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/schemas/_typescript.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/sql/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/sql/_sql_validation.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/validators/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/utils/validators/_validate_image_url.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/engine.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/operations/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/operations/builder.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/operations/context.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/operations/flow.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/operations/node.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/operations/registry.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/report.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/common/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/common/boolean.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/common/choice.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/common/mapping.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/common/model.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/common/number.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/common/string.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/registry.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/rule.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/rules/validator.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/src/krons/work/worker.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/agent/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/agent/test_mcps_unit.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/agent/test_message.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/agent/test_providers_e2e.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/agent/test_providers_unit.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/agent/test_tool_unit.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/conftest.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_broadcaster.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_element.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_error_paths.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_event.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_event_status_race.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_eventbus.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_flow.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_flow_edge_cases.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_graph.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_graph_event_loop.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_node.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_pile.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_pile_edge_cases.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_processor.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_processor_security.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_progression.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_progression_edge_cases.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_serialization_roundtrip.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/core/test_thread_safety_stress.py +0 -0
- {krons-0.2.0/tests/enforcement → krons-0.2.1/tests/operations}/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/operations/test_builder.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/operations/test_flow.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/operations/test_node.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/operations/test_op_flow.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/operations/test_op_node.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/operations/test_registry.py +0 -0
- {krons-0.2.0/tests/operations → krons-0.2.1/tests/resource}/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/resource/test_backend.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/resource/test_endpoint.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/resource/test_hook.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/resource/test_imodel.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/resource/test_registry.py +0 -0
- {krons-0.2.0/tests/resource → krons-0.2.1/tests/resource/utilities}/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/resource/utilities/test_header_factory.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/resource/utilities/test_rate_limiter.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/resource/utilities/test_resilience.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/resource/utilities/test_resilience_retry.py +0 -0
- {krons-0.2.0/tests/resource/utilities → krons-0.2.1/tests/rules}/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/rules/test_base.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/rules/test_builtin.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/rules/test_registry.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/rules/test_rule_params_edge_cases.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/rules/test_rules_comprehensive.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/rules/test_validator.py +0 -0
- {krons-0.2.0/tests/rules → krons-0.2.1/tests/session}/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/session/test_exchange.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/session/test_message.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/session/test_message_edge_cases.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/session/test_session.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/session/test_session_edge_cases.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/specs/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/specs/test_catalog.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/specs/test_factory.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/test_protocols.py +0 -0
- {krons-0.2.0/tests/session → krons-0.2.1/tests/types}/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/conftest.py +0 -0
- {krons-0.2.0/tests/types → krons-0.2.1/tests/types/spec_adapters}/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/spec_adapters/test_adapters_py311.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/spec_adapters/test_protocol.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/spec_adapters/test_pydantic_field.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/spec_adapters/test_sql_ddl_specs.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/test_db_types.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/test_identity.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/test_model.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/test_operable.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/test_sentinel.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/test_spec.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/test_types.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/types/test_types_py311.py +0 -0
- {krons-0.2.0/tests/types/spec_adapters → krons-0.2.1/tests/utils}/__init__.py +0 -0
- {krons-0.2.0/tests/utils → krons-0.2.1/tests/utils/concurrency}/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/concurrency/test_async_call.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/concurrency/test_cancel.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/concurrency/test_errors.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/concurrency/test_patterns.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/concurrency/test_primitives.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/concurrency/test_priority_queue.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/concurrency/test_run_async.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/concurrency/test_task.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/concurrency/test_utils.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_extract_json.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_fuzzy_json.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_fuzzy_match.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_hash.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_json_dump.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_lazy_init.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_sql_validation.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_string_similarity.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_to_dict.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_to_list.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_to_num.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/utils/test_utils.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/work/__init__.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/work/test_engine.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/work/test_report.py +0 -0
- {krons-0.2.0 → krons-0.2.1}/tests/work/test_worker.py +0 -0
|
@@ -32,7 +32,6 @@ Two complementary patterns at different abstraction levels:
|
|
|
32
32
|
return await self.llm.chat(**kwargs)
|
|
33
33
|
|
|
34
34
|
Core concepts:
|
|
35
|
-
- Phrase: Typed operation signature (inputs -> outputs)
|
|
36
35
|
- Form: Data binding + scheduling (stateful artifact)
|
|
37
36
|
- Report: Multi-step workflow declaration (stateful artifact)
|
|
38
37
|
- Worker: Execution capability (stateless station)
|
|
@@ -53,11 +52,6 @@ _LAZY_IMPORTS: dict[str, tuple[str, str]] = {
|
|
|
53
52
|
"ParsedAssignment": ("krons.work.form", "ParsedAssignment"),
|
|
54
53
|
"parse_assignment": ("krons.work.form", "parse_assignment"),
|
|
55
54
|
"parse_full_assignment": ("krons.work.form", "parse_full_assignment"),
|
|
56
|
-
# phrase
|
|
57
|
-
"CrudOperation": ("krons.work.phrase", "CrudOperation"),
|
|
58
|
-
"CrudPattern": ("krons.work.phrase", "CrudPattern"),
|
|
59
|
-
"Phrase": ("krons.work.phrase", "Phrase"),
|
|
60
|
-
"phrase": ("krons.work.phrase", "phrase"),
|
|
61
55
|
# report
|
|
62
56
|
"Report": ("krons.work.report", "Report"),
|
|
63
57
|
# worker
|
|
@@ -102,16 +96,12 @@ if TYPE_CHECKING:
|
|
|
102
96
|
parse_assignment,
|
|
103
97
|
parse_full_assignment,
|
|
104
98
|
)
|
|
105
|
-
from krons.work.phrase import CrudOperation, CrudPattern, Phrase, phrase
|
|
106
99
|
from krons.work.report import Report
|
|
107
100
|
from krons.work.worker import WorkConfig, Worker, WorkLink, work, worklink
|
|
108
101
|
|
|
109
102
|
__all__ = (
|
|
110
|
-
"CrudOperation",
|
|
111
|
-
"CrudPattern",
|
|
112
103
|
"Form",
|
|
113
104
|
"ParsedAssignment",
|
|
114
|
-
"Phrase",
|
|
115
105
|
"Report",
|
|
116
106
|
"WorkConfig",
|
|
117
107
|
"WorkLink",
|
|
@@ -120,7 +110,6 @@ __all__ = (
|
|
|
120
110
|
"WorkerTask",
|
|
121
111
|
"parse_assignment",
|
|
122
112
|
"parse_full_assignment",
|
|
123
|
-
"phrase",
|
|
124
113
|
"work",
|
|
125
114
|
"worklink",
|
|
126
115
|
)
|
|
@@ -6,23 +6,19 @@
|
|
|
6
6
|
A Form represents an instantiated work unit with:
|
|
7
7
|
- Data binding (input values)
|
|
8
8
|
- Execution state tracking (filled, workable)
|
|
9
|
-
- Optional Phrase reference for typed I/O
|
|
10
9
|
|
|
11
|
-
Forms are the stateful layer
|
|
10
|
+
Forms are the stateful scheduling layer for Operations.
|
|
12
11
|
"""
|
|
13
12
|
|
|
14
13
|
from __future__ import annotations
|
|
15
14
|
|
|
16
15
|
from dataclasses import dataclass
|
|
17
|
-
from typing import
|
|
16
|
+
from typing import Any
|
|
18
17
|
|
|
19
18
|
from pydantic import Field
|
|
20
19
|
|
|
21
20
|
from krons.core import Element
|
|
22
21
|
|
|
23
|
-
if TYPE_CHECKING:
|
|
24
|
-
from .phrase import Phrase
|
|
25
|
-
|
|
26
22
|
__all__ = ("Form", "ParsedAssignment", "parse_assignment", "parse_full_assignment")
|
|
27
23
|
|
|
28
24
|
|
|
@@ -123,9 +119,7 @@ def parse_full_assignment(assignment: str) -> ParsedAssignment:
|
|
|
123
119
|
class Form(Element):
|
|
124
120
|
"""Data binding container for work units.
|
|
125
121
|
|
|
126
|
-
A Form binds input data and tracks execution state.
|
|
127
|
-
1. From a Phrase (typed I/O)
|
|
128
|
-
2. From an assignment string (dynamic fields)
|
|
122
|
+
A Form binds input data and tracks execution state.
|
|
129
123
|
|
|
130
124
|
Assignment DSL supports full format:
|
|
131
125
|
"branch: inputs -> outputs | resource"
|
|
@@ -144,7 +138,6 @@ class Form(Element):
|
|
|
144
138
|
available_data: Current data values
|
|
145
139
|
output: Execution result
|
|
146
140
|
filled: Whether form has been executed
|
|
147
|
-
phrase: Optional Phrase reference for typed execution
|
|
148
141
|
"""
|
|
149
142
|
|
|
150
143
|
assignment: str = Field(
|
|
@@ -165,9 +158,6 @@ class Form(Element):
|
|
|
165
158
|
output: Any = Field(default=None)
|
|
166
159
|
filled: bool = Field(default=False)
|
|
167
160
|
|
|
168
|
-
# Optional phrase reference (set via from_phrase())
|
|
169
|
-
_phrase: "Phrase | None" = None
|
|
170
|
-
|
|
171
161
|
def model_post_init(self, _: Any) -> None:
|
|
172
162
|
"""Parse assignment to derive fields if not already set."""
|
|
173
163
|
if self.assignment and not self.input_fields and not self.output_fields:
|
|
@@ -179,35 +169,6 @@ class Form(Element):
|
|
|
179
169
|
if parsed.resource and self.resource is None:
|
|
180
170
|
self.resource = parsed.resource
|
|
181
171
|
|
|
182
|
-
@classmethod
|
|
183
|
-
def from_phrase(
|
|
184
|
-
cls,
|
|
185
|
-
phrase: "Phrase",
|
|
186
|
-
**initial_data: Any,
|
|
187
|
-
) -> "Form":
|
|
188
|
-
"""Create Form from a Phrase with optional initial data.
|
|
189
|
-
|
|
190
|
-
Args:
|
|
191
|
-
phrase: Phrase defining typed I/O
|
|
192
|
-
**initial_data: Initial input values
|
|
193
|
-
|
|
194
|
-
Returns:
|
|
195
|
-
Form bound to the phrase
|
|
196
|
-
"""
|
|
197
|
-
form = cls(
|
|
198
|
-
assignment=f"{', '.join(phrase.inputs)} -> {', '.join(phrase.outputs)}",
|
|
199
|
-
input_fields=list(phrase.inputs),
|
|
200
|
-
output_fields=list(phrase.outputs),
|
|
201
|
-
available_data=dict(initial_data),
|
|
202
|
-
)
|
|
203
|
-
form._phrase = phrase
|
|
204
|
-
return form
|
|
205
|
-
|
|
206
|
-
@property
|
|
207
|
-
def phrase(self) -> "Phrase | None":
|
|
208
|
-
"""Get bound phrase if any."""
|
|
209
|
-
return self._phrase
|
|
210
|
-
|
|
211
172
|
def is_workable(self) -> bool:
|
|
212
173
|
"""Check if form is ready for execution.
|
|
213
174
|
|
|
@@ -274,32 +235,8 @@ class Form(Element):
|
|
|
274
235
|
result[field] = self.available_data[field]
|
|
275
236
|
return result
|
|
276
237
|
|
|
277
|
-
async def execute(self, ctx: Any = None) -> Any:
|
|
278
|
-
"""Execute the form if it has a bound phrase.
|
|
279
|
-
|
|
280
|
-
Args:
|
|
281
|
-
ctx: Execution context
|
|
282
|
-
|
|
283
|
-
Returns:
|
|
284
|
-
Execution result
|
|
285
|
-
|
|
286
|
-
Raises:
|
|
287
|
-
RuntimeError: If no phrase bound or form not workable
|
|
288
|
-
"""
|
|
289
|
-
if self._phrase is None:
|
|
290
|
-
raise RuntimeError("Form has no bound phrase - cannot execute")
|
|
291
|
-
|
|
292
|
-
if not self.is_workable():
|
|
293
|
-
missing = [f for f in self.input_fields if f not in self.available_data]
|
|
294
|
-
raise RuntimeError(f"Form not workable - missing inputs: {missing}")
|
|
295
|
-
|
|
296
|
-
result = await self._phrase(self.get_inputs(), ctx)
|
|
297
|
-
self.set_output(result)
|
|
298
|
-
return result
|
|
299
|
-
|
|
300
238
|
def __repr__(self) -> str:
|
|
301
239
|
status = (
|
|
302
240
|
"filled" if self.filled else ("ready" if self.is_workable() else "pending")
|
|
303
241
|
)
|
|
304
|
-
|
|
305
|
-
return f"Form('{self.assignment}', {status}{phrase_info})"
|
|
242
|
+
return f"Form('{self.assignment}', {status})"
|
|
@@ -9,9 +9,7 @@ from uuid import UUID, uuid4
|
|
|
9
9
|
|
|
10
10
|
import pytest
|
|
11
11
|
|
|
12
|
-
from krons.core.specs import Operable, Spec
|
|
13
12
|
from krons.work.form import Form, parse_assignment
|
|
14
|
-
from krons.work.phrase import Phrase
|
|
15
13
|
|
|
16
14
|
# =============================================================================
|
|
17
15
|
# Tests: parse_assignment
|
|
@@ -152,85 +150,6 @@ class TestFormCreation:
|
|
|
152
150
|
assert form.output is None
|
|
153
151
|
|
|
154
152
|
|
|
155
|
-
# =============================================================================
|
|
156
|
-
# Tests: Form.from_phrase
|
|
157
|
-
# =============================================================================
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
class TestFormFromPhrase:
|
|
161
|
-
"""Tests for Form.from_phrase factory."""
|
|
162
|
-
|
|
163
|
-
def test_from_phrase_basic(self):
|
|
164
|
-
"""Form.from_phrase should create form bound to phrase."""
|
|
165
|
-
spec1 = Spec(str, name="name")
|
|
166
|
-
spec2 = Spec(int, name="count")
|
|
167
|
-
op = Operable([spec1, spec2])
|
|
168
|
-
|
|
169
|
-
async def handler(options, ctx):
|
|
170
|
-
return {"count": len(options.name)}
|
|
171
|
-
|
|
172
|
-
p = Phrase(
|
|
173
|
-
name="count_chars",
|
|
174
|
-
operable=op,
|
|
175
|
-
inputs={"name"},
|
|
176
|
-
outputs={"count"},
|
|
177
|
-
handler=handler,
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
form = Form.from_phrase(p)
|
|
181
|
-
|
|
182
|
-
assert form.phrase is p
|
|
183
|
-
assert "name" in form.input_fields
|
|
184
|
-
assert "count" in form.output_fields
|
|
185
|
-
assert "name -> count" in form.assignment or "name" in form.assignment
|
|
186
|
-
|
|
187
|
-
def test_from_phrase_with_initial_data(self):
|
|
188
|
-
"""Form.from_phrase should accept initial data."""
|
|
189
|
-
spec1 = Spec(str, name="name")
|
|
190
|
-
spec2 = Spec(int, name="count")
|
|
191
|
-
op = Operable([spec1, spec2])
|
|
192
|
-
|
|
193
|
-
async def handler(options, ctx):
|
|
194
|
-
return {"count": len(options.name)}
|
|
195
|
-
|
|
196
|
-
p = Phrase(
|
|
197
|
-
name="count_chars",
|
|
198
|
-
operable=op,
|
|
199
|
-
inputs={"name"},
|
|
200
|
-
outputs={"count"},
|
|
201
|
-
handler=handler,
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
form = Form.from_phrase(p, name="hello")
|
|
205
|
-
|
|
206
|
-
assert form.available_data["name"] == "hello"
|
|
207
|
-
|
|
208
|
-
def test_from_phrase_phrase_property(self):
|
|
209
|
-
"""Form.phrase property should return bound phrase."""
|
|
210
|
-
spec1 = Spec(str, name="name")
|
|
211
|
-
spec2 = Spec(int, name="count")
|
|
212
|
-
op = Operable([spec1, spec2])
|
|
213
|
-
|
|
214
|
-
async def handler(options, ctx):
|
|
215
|
-
return {"count": 0}
|
|
216
|
-
|
|
217
|
-
p = Phrase(
|
|
218
|
-
name="test",
|
|
219
|
-
operable=op,
|
|
220
|
-
inputs={"name"},
|
|
221
|
-
outputs={"count"},
|
|
222
|
-
handler=handler,
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
form = Form.from_phrase(p)
|
|
226
|
-
assert form.phrase is p
|
|
227
|
-
|
|
228
|
-
def test_form_without_phrase(self):
|
|
229
|
-
"""Form without phrase should have phrase=None."""
|
|
230
|
-
form = Form(assignment="a -> b")
|
|
231
|
-
assert form.phrase is None
|
|
232
|
-
|
|
233
|
-
|
|
234
153
|
# =============================================================================
|
|
235
154
|
# Tests: Form.is_workable
|
|
236
155
|
# =============================================================================
|
|
@@ -468,70 +387,6 @@ class TestFormGetOutputData:
|
|
|
468
387
|
# =============================================================================
|
|
469
388
|
|
|
470
389
|
|
|
471
|
-
class TestFormExecute:
|
|
472
|
-
"""Tests for Form.execute async execution."""
|
|
473
|
-
|
|
474
|
-
@pytest.mark.anyio
|
|
475
|
-
async def test_execute_with_phrase(self):
|
|
476
|
-
"""execute should invoke bound phrase and set output."""
|
|
477
|
-
spec1 = Spec(str, name="name")
|
|
478
|
-
spec2 = Spec(int, name="length")
|
|
479
|
-
op = Operable([spec1, spec2])
|
|
480
|
-
|
|
481
|
-
async def handler(options, ctx):
|
|
482
|
-
return {"length": len(options.name)}
|
|
483
|
-
|
|
484
|
-
p = Phrase(
|
|
485
|
-
name="get_length",
|
|
486
|
-
operable=op,
|
|
487
|
-
inputs={"name"},
|
|
488
|
-
outputs={"length"},
|
|
489
|
-
handler=handler,
|
|
490
|
-
)
|
|
491
|
-
|
|
492
|
-
form = Form.from_phrase(p, name="hello")
|
|
493
|
-
|
|
494
|
-
result = await form.execute(ctx=None)
|
|
495
|
-
|
|
496
|
-
assert form.filled is True
|
|
497
|
-
assert form.available_data["length"] == 5
|
|
498
|
-
assert result.length == 5
|
|
499
|
-
|
|
500
|
-
@pytest.mark.anyio
|
|
501
|
-
async def test_execute_no_phrase_raises(self):
|
|
502
|
-
"""execute without bound phrase should raise RuntimeError."""
|
|
503
|
-
form = Form(
|
|
504
|
-
assignment="a -> b",
|
|
505
|
-
available_data={"a": 1},
|
|
506
|
-
)
|
|
507
|
-
|
|
508
|
-
with pytest.raises(RuntimeError, match="no bound phrase"):
|
|
509
|
-
await form.execute(ctx=None)
|
|
510
|
-
|
|
511
|
-
@pytest.mark.anyio
|
|
512
|
-
async def test_execute_not_workable_raises(self):
|
|
513
|
-
"""execute when not workable should raise RuntimeError."""
|
|
514
|
-
spec1 = Spec(str, name="name")
|
|
515
|
-
spec2 = Spec(int, name="length")
|
|
516
|
-
op = Operable([spec1, spec2])
|
|
517
|
-
|
|
518
|
-
async def handler(options, ctx):
|
|
519
|
-
return {"length": 0}
|
|
520
|
-
|
|
521
|
-
p = Phrase(
|
|
522
|
-
name="get_length",
|
|
523
|
-
operable=op,
|
|
524
|
-
inputs={"name"},
|
|
525
|
-
outputs={"length"},
|
|
526
|
-
handler=handler,
|
|
527
|
-
)
|
|
528
|
-
|
|
529
|
-
form = Form.from_phrase(p) # No data provided
|
|
530
|
-
|
|
531
|
-
with pytest.raises(RuntimeError, match="not workable"):
|
|
532
|
-
await form.execute(ctx=None)
|
|
533
|
-
|
|
534
|
-
|
|
535
390
|
# =============================================================================
|
|
536
391
|
# Tests: Form.__repr__
|
|
537
392
|
# =============================================================================
|
|
@@ -568,28 +423,6 @@ class TestFormRepr:
|
|
|
568
423
|
|
|
569
424
|
assert "filled" in repr_str
|
|
570
425
|
|
|
571
|
-
def test_repr_with_phrase(self):
|
|
572
|
-
"""repr should include phrase name when bound."""
|
|
573
|
-
spec1 = Spec(str, name="a")
|
|
574
|
-
spec2 = Spec(int, name="b")
|
|
575
|
-
op = Operable([spec1, spec2])
|
|
576
|
-
|
|
577
|
-
async def handler(options, ctx):
|
|
578
|
-
return {"b": 0}
|
|
579
|
-
|
|
580
|
-
p = Phrase(
|
|
581
|
-
name="test_phrase",
|
|
582
|
-
operable=op,
|
|
583
|
-
inputs={"a"},
|
|
584
|
-
outputs={"b"},
|
|
585
|
-
handler=handler,
|
|
586
|
-
)
|
|
587
|
-
|
|
588
|
-
form = Form.from_phrase(p)
|
|
589
|
-
repr_str = repr(form)
|
|
590
|
-
|
|
591
|
-
assert "test_phrase" in repr_str
|
|
592
|
-
|
|
593
426
|
|
|
594
427
|
# =============================================================================
|
|
595
428
|
# Tests: Form Element inheritance
|