lionagi 0.7.7__tar.gz → 0.8.0__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.
- {lionagi-0.7.7 → lionagi-0.8.0}/PKG-INFO +1 -1
- lionagi-0.8.0/docs/modules/form.rst +329 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/manager.py +1 -1
- lionagi-0.8.0/lionagi/operatives/forms/base.py +80 -0
- lionagi-0.8.0/lionagi/operatives/forms/flow.py +74 -0
- lionagi-0.8.0/lionagi/operatives/forms/form.py +82 -0
- lionagi-0.8.0/lionagi/operatives/forms/report.py +45 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/types.py +3 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/utils.py +4 -1
- lionagi-0.8.0/lionagi/version.py +1 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/pyproject.toml +1 -1
- lionagi-0.7.7/cookbooks/ch10_e2e_project.md +0 -521
- lionagi-0.7.7/cookbooks/ch11_performance.md +0 -509
- lionagi-0.7.7/cookbooks/ch12_graph.md +0 -583
- lionagi-0.7.7/cookbooks/ch3_internal_tools.md +0 -450
- lionagi-0.7.7/cookbooks/ch4_structured_forms.md +0 -674
- lionagi-0.7.7/cookbooks/ch5_react.md +0 -693
- lionagi-0.7.7/cookbooks/ch6_multi_branch.md +0 -806
- lionagi-0.7.7/cookbooks/ch7_multi_agent.md +0 -741
- lionagi-0.7.7/cookbooks/ch8_rate_limiting.md +0 -585
- lionagi-0.7.7/cookbooks/ch9_data_adapter.md +0 -581
- lionagi-0.7.7/docs/modules/form.rst +0 -193
- lionagi-0.7.7/lionagi/operatives/forms/base.py +0 -237
- lionagi-0.7.7/lionagi/operatives/forms/form.py +0 -786
- lionagi-0.7.7/lionagi/operatives/forms/report.py +0 -323
- lionagi-0.7.7/lionagi/operatives/forms/utils.py +0 -26
- lionagi-0.7.7/lionagi/version.py +0 -1
- {lionagi-0.7.7 → lionagi-0.8.0}/.env.example +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/.github/FUNDING.yml +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/.github/dependabot.yml +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/.github/workflows/ci.yml +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/.github/workflows/codeql.yml +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/.github/workflows/docs.yml +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/.github/workflows/release.yml +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/.gitignore +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/.pre-commit-config.yaml +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/CODE_OF_CONDUCT.md +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/CONTRIBUTING.md +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/LICENSE +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/README.md +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/cookbooks/ch01_get_started.md +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/cookbooks/ch02_concepts.md +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/dev_tools/count_code_base_lines.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/Makefile +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/_static/custom.css +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/_templates/layout.html +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/conf.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/index.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/action.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/adapter.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/branch.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/branch_operations.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/concepts.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/element_id.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/event.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/graph.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/index.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/instruct.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/lib_file.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/lib_nested.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/lib_package.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/lib_schema.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/lib_validate.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/log.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/mail.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/message.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/models.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/operative_step.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/pile.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/processor.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/progression.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/service.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/session.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/modules/utils.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/tutorials/get_started.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/tutorials/get_started_pt2.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/tutorials/get_started_pt3.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/docs/tutorials/index.rst +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/_class_registry.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/_errors.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/_types.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/file/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/file/chunk.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/file/file_ops.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/file/params.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/file/process.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/file/save.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/nested/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/nested/flatten.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/nested/nfilter.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/nested/nget.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/nested/ninsert.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/nested/nmerge.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/nested/npop.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/nested/nset.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/nested/unflatten.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/nested/utils.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/package/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/package/imports.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/package/management.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/package/params.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/package/system.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/parse.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/schema/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/schema/as_readable.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/schema/extract_code_block.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/schema/extract_docstring.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/schema/function_to_schema.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/schema/json_schema.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/token_transform/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/token_transform/llmlingua.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/token_transform/perplexity.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/token_transform/synthlang.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/validate/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/validate/common_field_validators.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/validate/fuzzy_match_keys.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/validate/fuzzy_validate_mapping.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/validate/string_similarity.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/libs/validate/validate_boolean.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/ReAct/ReAct.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/ReAct/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/ReAct/utils.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/_act/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/_act/act.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/brainstorm/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/brainstorm/brainstorm.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/brainstorm/prompt.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/chat/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/chat/chat.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/communicate/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/communicate/communicate.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/instruct/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/instruct/instruct.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/interpret/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/interpret/interpret.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/operate/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/operate/operate.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/parse/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/parse/parse.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/plan/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/plan/plan.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/plan/prompt.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/select/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/select/select.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/select/utils.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/translate/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/translate/translate.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/types.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operations/utils.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/action/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/action/function_calling.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/action/manager.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/action/request_response_model.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/action/tool.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/action/utils.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/forms/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/instruct/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/instruct/base.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/instruct/instruct.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/instruct/instruct_collection.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/instruct/node.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/instruct/prompts.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/instruct/reason.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/manager.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/models/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/models/field_model.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/models/model_params.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/models/note.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/models/operable_model.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/models/schema_model.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/operative.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/step.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/strategies/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/strategies/base.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/strategies/concurrent.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/strategies/concurrent_chunk.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/strategies/concurrent_sequential_chunk.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/strategies/params.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/strategies/sequential.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/strategies/sequential_chunk.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/strategies/sequential_concurrent_chunk.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/operatives/strategies/utils.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/_concepts.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/adapters/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/adapters/adapter.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/adapters/json_adapter.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/adapters/pandas_/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/adapters/pandas_/csv_adapter.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/adapters/pandas_/excel_adapter.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/adapters/pandas_/pd_dataframe_adapter.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/adapters/pandas_/pd_series_adapter.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/adapters/types.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/generic/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/generic/element.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/generic/event.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/generic/log.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/generic/pile.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/generic/processor.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/generic/progression.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/graph/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/graph/edge.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/graph/graph.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/graph/node.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/mail/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/mail/exchange.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/mail/mail.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/mail/mailbox.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/mail/manager.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/mail/package.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/action_request.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/action_response.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/assistant_response.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/base.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/instruction.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/manager.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/message.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/system.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/templates/README.md +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/templates/action_request.jinja2 +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/templates/action_response.jinja2 +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/templates/assistant_response.jinja2 +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/templates/instruction_message.jinja2 +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/templates/system_message.jinja2 +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/messages/templates/tool_schemas.jinja2 +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/protocols/types.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/endpoints/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/endpoints/base.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/endpoints/chat_completion.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/endpoints/match_endpoint.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/endpoints/rate_limited_processor.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/endpoints/token_calculator.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/imodel.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/manager.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/anthropic_/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/anthropic_/messages.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/exa_/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/exa_/models.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/exa_/search.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/exa_/types.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/groq_/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/groq_/chat_completions.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/openai_/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/openai_/chat_completions.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/openrouter_/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/openrouter_/chat_completions.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/perplexity_/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/perplexity_/chat_completions.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/providers/types.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/service/types.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/session/__init__.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/session/branch.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/session/session.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/lionagi/settings.py +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/prompts/doc_style.md +0 -0
- {lionagi-0.7.7 → lionagi-0.8.0}/uv.lock +0 -0
@@ -0,0 +1,329 @@
|
|
1
|
+
======================================
|
2
|
+
Form & Flow
|
3
|
+
======================================
|
4
|
+
|
5
|
+
The forms module provides a flexible system for handling structured data transformations
|
6
|
+
through forms and multi-step flows. It consists of four core components:
|
7
|
+
|
8
|
+
1. :class:`BaseForm` - Foundation for form handling
|
9
|
+
2. :class:`Form` - Enhanced form with input/output field distinction
|
10
|
+
3. :class:`FlowDefinition` - Multi-step transformation pipeline
|
11
|
+
4. :class:`Report` - Aggregator for completed forms
|
12
|
+
|
13
|
+
-----------
|
14
|
+
Base Form
|
15
|
+
-----------
|
16
|
+
|
17
|
+
.. module:: lionagi.operatives.forms.base
|
18
|
+
:synopsis: Core form functionality.
|
19
|
+
|
20
|
+
.. class:: BaseForm
|
21
|
+
|
22
|
+
**Inherits from**: :class:`lionagi.protocols.generic.element.Element`
|
23
|
+
|
24
|
+
A minimal form class that tracks output fields and validates completeness.
|
25
|
+
Uses Pydantic v2 with ``ConfigDict(extra="allow", arbitrary_types_allowed=True)``.
|
26
|
+
|
27
|
+
**Attributes**:
|
28
|
+
|
29
|
+
- **assignment** (*str | None*) -- A DSL string describing the transformation
|
30
|
+
- **output_fields** (*list[str]*) -- Fields considered mandatory outputs
|
31
|
+
- **none_as_valid** (*bool*) -- If True, None is accepted as valid
|
32
|
+
- **has_processed** (*bool*) -- Marks if form is completed
|
33
|
+
|
34
|
+
**Methods**:
|
35
|
+
|
36
|
+
.. method:: is_completed() -> bool
|
37
|
+
|
38
|
+
Check if all required output fields are set and valid.
|
39
|
+
A field is considered valid if:
|
40
|
+
|
41
|
+
- It exists and has a value
|
42
|
+
- The value is not UNDEFINED
|
43
|
+
- If none_as_valid=False, the value is not None
|
44
|
+
|
45
|
+
.. method:: check_completeness(how: Literal["raise", "return_missing"]) -> list[str]
|
46
|
+
|
47
|
+
Return missing required fields or raise an exception.
|
48
|
+
|
49
|
+
Parameters:
|
50
|
+
- **how** -- If "raise", raises ValueError for missing fields.
|
51
|
+
If "return_missing", returns list of missing field names.
|
52
|
+
|
53
|
+
.. method:: get_results(valid_only: bool = False) -> dict[str, Any]
|
54
|
+
|
55
|
+
Return a dict of output fields, optionally filtering invalid values.
|
56
|
+
|
57
|
+
Parameters:
|
58
|
+
- **valid_only** -- If True, omit fields with None/UNDEFINED values
|
59
|
+
(depending on none_as_valid setting)
|
60
|
+
|
61
|
+
**Example**::
|
62
|
+
|
63
|
+
from lionagi.operatives.forms import BaseForm
|
64
|
+
|
65
|
+
form = BaseForm(
|
66
|
+
output_fields=["result"],
|
67
|
+
none_as_valid=False
|
68
|
+
)
|
69
|
+
form.result = "computation complete"
|
70
|
+
assert form.is_completed()
|
71
|
+
print(form.get_results()) # {"result": "computation complete"}
|
72
|
+
|
73
|
+
# With none_as_valid=True
|
74
|
+
form = BaseForm(
|
75
|
+
output_fields=["optional_result"],
|
76
|
+
none_as_valid=True
|
77
|
+
)
|
78
|
+
form.optional_result = None
|
79
|
+
assert form.is_completed() # True, None is valid
|
80
|
+
|
81
|
+
-----------
|
82
|
+
Flow System
|
83
|
+
-----------
|
84
|
+
|
85
|
+
.. module:: lionagi.operatives.forms.flow
|
86
|
+
:synopsis: Multi-step flow handling.
|
87
|
+
|
88
|
+
.. class:: FlowStep
|
89
|
+
|
90
|
+
**Inherits from**: :class:`pydantic.BaseModel`
|
91
|
+
|
92
|
+
A single transformation step in a multi-step flow.
|
93
|
+
Uses Pydantic v2 with ``ConfigDict(arbitrary_types_allowed=True)``.
|
94
|
+
|
95
|
+
**Attributes**:
|
96
|
+
|
97
|
+
- **name** (*str*) -- Step identifier (e.g., "step_1")
|
98
|
+
- **inputs** (*list[str]*) -- Required input fields for this step
|
99
|
+
- **outputs** (*list[str]*) -- Fields produced by this step
|
100
|
+
- **description** (*str | None*) -- Optional step documentation
|
101
|
+
|
102
|
+
.. class:: FlowDefinition
|
103
|
+
|
104
|
+
**Inherits from**: :class:`pydantic.BaseModel`
|
105
|
+
|
106
|
+
Manages a sequence of transformation steps using a DSL.
|
107
|
+
Uses Pydantic v2 with ``ConfigDict(arbitrary_types_allowed=True)``.
|
108
|
+
|
109
|
+
**Attributes**:
|
110
|
+
|
111
|
+
- **steps** (*List[FlowStep]*) -- Ordered list of transformation steps
|
112
|
+
|
113
|
+
**Methods**:
|
114
|
+
|
115
|
+
.. method:: parse_flow_string(flow_str: str)
|
116
|
+
|
117
|
+
Parse a DSL string like "a,b->c; c->d" into FlowSteps.
|
118
|
+
Each step is named sequentially (step_1, step_2, etc.).
|
119
|
+
Empty segments and whitespace are handled gracefully.
|
120
|
+
|
121
|
+
.. method:: get_required_fields() -> set[str]
|
122
|
+
|
123
|
+
Return fields needed as inputs but not produced by prior steps.
|
124
|
+
For example, in "a->b; b,c->d", returns {"a", "c"} since:
|
125
|
+
|
126
|
+
- "a" is needed by step 1 but not produced earlier
|
127
|
+
- "b" is needed by step 2 but produced by step 1
|
128
|
+
- "c" is needed by step 2 but not produced earlier
|
129
|
+
|
130
|
+
.. method:: get_produced_fields() -> set[str]
|
131
|
+
|
132
|
+
Return all fields produced by any step.
|
133
|
+
For example, in "a->b,c; c->d", returns {"b", "c", "d"}.
|
134
|
+
|
135
|
+
**Example**::
|
136
|
+
|
137
|
+
from lionagi.operatives.forms import FlowDefinition
|
138
|
+
|
139
|
+
flow = FlowDefinition()
|
140
|
+
|
141
|
+
# Parse text processing pipeline
|
142
|
+
flow.parse_flow_string(
|
143
|
+
"text->tokens; tokens->embeddings; embeddings->clusters"
|
144
|
+
)
|
145
|
+
|
146
|
+
print(flow.get_required_fields()) # {"text"}
|
147
|
+
print(flow.get_produced_fields()) # {"tokens", "embeddings", "clusters"}
|
148
|
+
|
149
|
+
# Steps are named sequentially
|
150
|
+
for step in flow.steps:
|
151
|
+
print(f"{step.name}: {step.inputs} -> {step.outputs}")
|
152
|
+
|
153
|
+
------
|
154
|
+
Form
|
155
|
+
------
|
156
|
+
|
157
|
+
.. module:: lionagi.operatives.forms.form
|
158
|
+
:synopsis: Enhanced form with input/output distinction.
|
159
|
+
|
160
|
+
.. class:: Form
|
161
|
+
|
162
|
+
**Inherits from**: :class:`BaseForm`
|
163
|
+
|
164
|
+
A form that distinguishes between input and request (output) fields.
|
165
|
+
Uses Pydantic v2 with ``ConfigDict(extra="allow", arbitrary_types_allowed=True)``.
|
166
|
+
|
167
|
+
**Attributes**:
|
168
|
+
|
169
|
+
- **flow_definition** (*Optional[FlowDefinition]*) -- For multi-step flows
|
170
|
+
- **guidance** (*str | None*) -- Optional processing guidance
|
171
|
+
- **task** (*str | None*) -- Task description
|
172
|
+
|
173
|
+
**Validators**:
|
174
|
+
|
175
|
+
- **parse_assignment_into_flow**: Creates FlowDefinition for multi-step assignments
|
176
|
+
- **compute_output_fields**: Sets output_fields based on assignment or flow
|
177
|
+
|
178
|
+
**Methods**:
|
179
|
+
|
180
|
+
.. method:: fill_fields(**kwargs)
|
181
|
+
|
182
|
+
Update form fields with provided values.
|
183
|
+
Useful for partial updates when you don't want to recreate the form.
|
184
|
+
|
185
|
+
.. method:: to_instructions() -> dict[str, Any]
|
186
|
+
|
187
|
+
Return a dictionary suitable for LLM consumption, containing:
|
188
|
+
|
189
|
+
- assignment: The DSL string
|
190
|
+
- flow: FlowDefinition as dict (if multi-step)
|
191
|
+
- guidance: Optional processing guidance
|
192
|
+
- task: Optional task description
|
193
|
+
- required_outputs: List of required output fields
|
194
|
+
|
195
|
+
**Example**::
|
196
|
+
|
197
|
+
from lionagi.operatives.forms import Form
|
198
|
+
|
199
|
+
# Single-step form
|
200
|
+
form = Form(assignment="user_input->greeting")
|
201
|
+
form.fill_fields(user_input="Alice")
|
202
|
+
|
203
|
+
# Multi-step form with all produced fields as outputs
|
204
|
+
form = Form(
|
205
|
+
assignment="name,age->profile; profile->recommendation",
|
206
|
+
guidance="Generate personalized recommendations",
|
207
|
+
task="User profiling"
|
208
|
+
)
|
209
|
+
|
210
|
+
# The flow is automatically parsed
|
211
|
+
assert form.flow_definition is not None
|
212
|
+
assert len(form.flow_definition.steps) == 2
|
213
|
+
|
214
|
+
# All produced fields are outputs
|
215
|
+
assert set(form.output_fields) == {"profile", "recommendation"}
|
216
|
+
|
217
|
+
--------
|
218
|
+
Report
|
219
|
+
--------
|
220
|
+
|
221
|
+
.. module:: lionagi.operatives.forms.report
|
222
|
+
:synopsis: Form aggregation and tracking.
|
223
|
+
|
224
|
+
.. class:: Report
|
225
|
+
|
226
|
+
**Inherits from**: :class:`BaseForm`
|
227
|
+
|
228
|
+
Collects and manages multiple completed forms.
|
229
|
+
Uses Pydantic v2 with ``ConfigDict(extra="allow", arbitrary_types_allowed=True)``.
|
230
|
+
|
231
|
+
**Attributes**:
|
232
|
+
|
233
|
+
- **default_form_cls** (*type[Form]*) -- Form class to use (defaults to Form)
|
234
|
+
- **completed_forms** (*Pile[Form]*) -- Thread-safe collection of completed forms
|
235
|
+
- **form_assignments** (*dict[str, str]*) -- Maps form IDs to assignments
|
236
|
+
|
237
|
+
**Methods**:
|
238
|
+
|
239
|
+
.. method:: add_completed_form(form: Form, update_report_fields: bool = False)
|
240
|
+
|
241
|
+
Add a completed form to the report.
|
242
|
+
|
243
|
+
Parameters:
|
244
|
+
- **form** -- A completed Form instance
|
245
|
+
- **update_report_fields** -- If True, copy form's output values to report
|
246
|
+
|
247
|
+
Raises:
|
248
|
+
- ValueError if form is incomplete
|
249
|
+
|
250
|
+
**Example**::
|
251
|
+
|
252
|
+
from lionagi.operatives.forms import Report, Form
|
253
|
+
|
254
|
+
report = Report()
|
255
|
+
|
256
|
+
# Create and complete forms for a multi-step process
|
257
|
+
form1 = Form(assignment="query->embeddings")
|
258
|
+
form1.fill_fields(
|
259
|
+
query="What's the weather?",
|
260
|
+
embeddings=[0.1, 0.2, 0.3]
|
261
|
+
)
|
262
|
+
|
263
|
+
form2 = Form(assignment="embeddings->answer")
|
264
|
+
form2.fill_fields(
|
265
|
+
embeddings=form1.embeddings,
|
266
|
+
answer="Sunny with a high of 75°F"
|
267
|
+
)
|
268
|
+
|
269
|
+
# Add both forms, updating report fields from the final form
|
270
|
+
report.add_completed_form(form1)
|
271
|
+
report.add_completed_form(form2, update_report_fields=True)
|
272
|
+
|
273
|
+
print(report.answer) # "Sunny with a high of 75°F"
|
274
|
+
|
275
|
+
--------------------
|
276
|
+
Additional Notes
|
277
|
+
--------------------
|
278
|
+
|
279
|
+
**DSL Format**
|
280
|
+
|
281
|
+
The forms system uses a simple DSL (Domain Specific Language) for describing
|
282
|
+
transformations:
|
283
|
+
|
284
|
+
- Single step: ``input1, input2 -> output``
|
285
|
+
- Multiple steps: ``a,b->c; c->d``
|
286
|
+
- Spaces are allowed: ``input1, input2 -> output``
|
287
|
+
|
288
|
+
The DSL is parsed into either:
|
289
|
+
|
290
|
+
1. Simple input/output field lists for :class:`Form`
|
291
|
+
2. A full :class:`FlowDefinition` for multi-step processes
|
292
|
+
|
293
|
+
**Multi-step Flow Behavior**
|
294
|
+
|
295
|
+
When using multi-step flows:
|
296
|
+
|
297
|
+
1. Each step's outputs become available to later steps as inputs
|
298
|
+
2. The form's output_fields include all produced fields by default
|
299
|
+
3. You can override output_fields to select specific outputs
|
300
|
+
4. Required fields are those needed as inputs but not produced by prior steps
|
301
|
+
|
302
|
+
**Best Practices**
|
303
|
+
|
304
|
+
1. Use :class:`BaseForm` when you only need output validation
|
305
|
+
2. Use :class:`Form` when distinguishing inputs from outputs
|
306
|
+
3. Use :class:`FlowDefinition` for complex multi-step transformations
|
307
|
+
4. Use :class:`Report` to track multiple related forms
|
308
|
+
5. Set none_as_valid=True when fields may legitimately be None
|
309
|
+
6. Provide guidance and task descriptions for better LLM interaction
|
310
|
+
|
311
|
+
**Type Safety**
|
312
|
+
|
313
|
+
All form classes use Pydantic v2 for validation. You can create typed forms by
|
314
|
+
subclassing and adding type hints::
|
315
|
+
|
316
|
+
from pydantic import Field
|
317
|
+
from lionagi.utils import UNDEFINED
|
318
|
+
|
319
|
+
class UserForm(Form):
|
320
|
+
name: str = Field(default=UNDEFINED)
|
321
|
+
age: int = Field(default=UNDEFINED)
|
322
|
+
profile: str | None = Field(default=None)
|
323
|
+
|
324
|
+
model_config = ConfigDict(
|
325
|
+
extra="allow",
|
326
|
+
arbitrary_types_allowed=True
|
327
|
+
)
|
328
|
+
|
329
|
+
This ensures type safety and proper validation for form fields.
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# forms/base_form.py
|
2
|
+
|
3
|
+
from typing import Any, Literal
|
4
|
+
|
5
|
+
from pydantic import ConfigDict, Field
|
6
|
+
from pydantic_core import PydanticUndefined
|
7
|
+
|
8
|
+
from lionagi.protocols.generic.element import Element
|
9
|
+
from lionagi.utils import UNDEFINED
|
10
|
+
|
11
|
+
|
12
|
+
class BaseForm(Element):
|
13
|
+
"""
|
14
|
+
A minimal base form class to store fields and define output logic.
|
15
|
+
Typically, you'll inherit from this for domain-specific forms.
|
16
|
+
"""
|
17
|
+
|
18
|
+
model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True)
|
19
|
+
|
20
|
+
# A short "assignment" describing input->output
|
21
|
+
assignment: str | None = Field(
|
22
|
+
default=None,
|
23
|
+
description="A small DSL describing transformation, e.g. 'a,b -> c'.",
|
24
|
+
)
|
25
|
+
# Which fields are produced as 'final' or 'required' outputs.
|
26
|
+
output_fields: list[str] = Field(
|
27
|
+
default_factory=list,
|
28
|
+
description="Which fields are considered mandatory outputs.",
|
29
|
+
)
|
30
|
+
# Whether None counts as valid or incomplete
|
31
|
+
none_as_valid: bool = Field(
|
32
|
+
default=False,
|
33
|
+
description="If True, None is accepted as a valid value for completion checks.",
|
34
|
+
)
|
35
|
+
has_processed: bool = Field(
|
36
|
+
default=False,
|
37
|
+
description="Marks if the form is considered completed or 'processed'.",
|
38
|
+
)
|
39
|
+
|
40
|
+
def is_completed(self) -> bool:
|
41
|
+
"""Check if all required output fields are set (and not UNDEFINED/None if not allowed)."""
|
42
|
+
missing = self.check_completeness()
|
43
|
+
return not missing
|
44
|
+
|
45
|
+
def check_completeness(
|
46
|
+
self, how: Literal["raise", "return_missing"] = "return_missing"
|
47
|
+
) -> list[str]:
|
48
|
+
"""
|
49
|
+
Return a list of any 'required' output fields that are missing or invalid.
|
50
|
+
If how='raise', raise an exception if missing any.
|
51
|
+
"""
|
52
|
+
invalid_vals = [UNDEFINED, PydanticUndefined]
|
53
|
+
if not self.none_as_valid:
|
54
|
+
invalid_vals.append(None)
|
55
|
+
|
56
|
+
missing = []
|
57
|
+
for f in self.output_fields:
|
58
|
+
val = getattr(self, f, UNDEFINED)
|
59
|
+
if val in invalid_vals:
|
60
|
+
missing.append(f)
|
61
|
+
|
62
|
+
if missing and how == "raise":
|
63
|
+
raise ValueError(f"Form missing required fields: {missing}")
|
64
|
+
return missing
|
65
|
+
|
66
|
+
def get_results(self, valid_only: bool = False) -> dict[str, Any]:
|
67
|
+
"""
|
68
|
+
Return a dict of all `output_fields`, optionally skipping invalid/None if `valid_only`.
|
69
|
+
"""
|
70
|
+
results = {}
|
71
|
+
invalid_vals = [UNDEFINED, PydanticUndefined]
|
72
|
+
if not self.none_as_valid:
|
73
|
+
invalid_vals.append(None)
|
74
|
+
|
75
|
+
for f in self.output_fields:
|
76
|
+
val = getattr(self, f, UNDEFINED)
|
77
|
+
if valid_only and val in invalid_vals:
|
78
|
+
continue
|
79
|
+
results[f] = val
|
80
|
+
return results
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# forms/flow.py
|
2
|
+
from typing import List
|
3
|
+
|
4
|
+
from pydantic import BaseModel, ConfigDict, Field
|
5
|
+
|
6
|
+
|
7
|
+
class FlowStep(BaseModel):
|
8
|
+
"""
|
9
|
+
A minimal 'step' describing one transformation from some input fields to some output fields.
|
10
|
+
"""
|
11
|
+
|
12
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
13
|
+
|
14
|
+
name: str = Field(..., description="Identifier for the step.")
|
15
|
+
inputs: list[str] = Field(
|
16
|
+
..., description="Which fields are needed for this step."
|
17
|
+
)
|
18
|
+
outputs: list[str] = Field(
|
19
|
+
..., description="Which fields are produced by this step."
|
20
|
+
)
|
21
|
+
description: str | None = None # optional text doc
|
22
|
+
|
23
|
+
|
24
|
+
class FlowDefinition(BaseModel):
|
25
|
+
"""
|
26
|
+
A minimal DSL-based multi-step flow, e.g. 'a,b->c; c->d' to yield two steps.
|
27
|
+
"""
|
28
|
+
|
29
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
30
|
+
|
31
|
+
steps: list[FlowStep] = Field(default_factory=list)
|
32
|
+
|
33
|
+
def parse_flow_string(self, flow_str: str):
|
34
|
+
"""
|
35
|
+
Parse a string like 'a,b->c; c->d' into multiple FlowSteps.
|
36
|
+
We'll store them in self.steps in order.
|
37
|
+
"""
|
38
|
+
if not flow_str:
|
39
|
+
return
|
40
|
+
segments = [seg.strip() for seg in flow_str.split(";") if seg.strip()]
|
41
|
+
for i, seg in enumerate(segments):
|
42
|
+
# seg might be like 'a,b->c' or 'a->b, c' etc
|
43
|
+
if "->" not in seg:
|
44
|
+
raise ValueError(f"Invalid DSL segment (no '->'): '{seg}'")
|
45
|
+
ins_str, outs_str = seg.split("->", 1)
|
46
|
+
inputs = [x.strip() for x in ins_str.split(",") if x.strip()]
|
47
|
+
outputs = [y.strip() for y in outs_str.split(",") if y.strip()]
|
48
|
+
step = FlowStep(name=f"step_{i+1}", inputs=inputs, outputs=outputs)
|
49
|
+
self.steps.append(step)
|
50
|
+
|
51
|
+
def get_required_fields(self) -> set[str]:
|
52
|
+
"""
|
53
|
+
Return all fields that are used as inputs in the earliest steps but not produced by prior steps.
|
54
|
+
This is a minimal approach; or we can do more advanced logic if needed.
|
55
|
+
"""
|
56
|
+
produced = set()
|
57
|
+
required = set()
|
58
|
+
for step in self.steps:
|
59
|
+
# anything not yet produced is needed
|
60
|
+
for i in step.inputs:
|
61
|
+
if i not in produced:
|
62
|
+
required.add(i)
|
63
|
+
for o in step.outputs:
|
64
|
+
produced.add(o)
|
65
|
+
return required
|
66
|
+
|
67
|
+
def get_produced_fields(self) -> set[str]:
|
68
|
+
"""
|
69
|
+
Return all fields that eventually get produced by any step.
|
70
|
+
"""
|
71
|
+
result = set()
|
72
|
+
for st in self.steps:
|
73
|
+
result.update(st.outputs)
|
74
|
+
return result
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# forms/form.py
|
2
|
+
|
3
|
+
from typing import Any, Optional
|
4
|
+
|
5
|
+
from pydantic import ConfigDict, Field, model_validator
|
6
|
+
from typing_extensions import Self
|
7
|
+
|
8
|
+
from .base import BaseForm
|
9
|
+
from .flow import FlowDefinition
|
10
|
+
|
11
|
+
|
12
|
+
class Form(BaseForm):
|
13
|
+
"""
|
14
|
+
A domain form that can handle either a simple 'a,b->c' assignment
|
15
|
+
or a multi-step flow if the assignment string has semicolons, etc.
|
16
|
+
"""
|
17
|
+
|
18
|
+
model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True)
|
19
|
+
|
20
|
+
flow_definition: FlowDefinition | None = None
|
21
|
+
# Possibly some extra fields, e.g. "guidance" or "task"
|
22
|
+
guidance: str | None = Field(default=None)
|
23
|
+
task: str | None = Field(default=None)
|
24
|
+
|
25
|
+
@model_validator(mode="before")
|
26
|
+
def parse_assignment_into_flow(cls, values):
|
27
|
+
"""
|
28
|
+
If the 'assignment' has semicolons, assume multiple steps, parse into FlowDefinition.
|
29
|
+
If it's a single step or no semicolons, we remain in 'simple' mode.
|
30
|
+
"""
|
31
|
+
assignment_str = values.get("assignment")
|
32
|
+
if assignment_str and ";" in assignment_str:
|
33
|
+
flow = FlowDefinition()
|
34
|
+
flow.parse_flow_string(assignment_str)
|
35
|
+
values["flow_definition"] = flow
|
36
|
+
return values
|
37
|
+
|
38
|
+
@model_validator(mode="after")
|
39
|
+
def compute_output_fields(self) -> Self:
|
40
|
+
"""
|
41
|
+
If in simple mode, we parse something like 'a,b->c' and set output_fields=[c].
|
42
|
+
If in multi-step mode, we set output_fields to the final produced fields of the flow.
|
43
|
+
"""
|
44
|
+
if self.flow_definition:
|
45
|
+
# multi-step
|
46
|
+
produced = self.flow_definition.get_produced_fields()
|
47
|
+
if not self.output_fields:
|
48
|
+
self.output_fields = list(produced)
|
49
|
+
else:
|
50
|
+
# single-step
|
51
|
+
if self.assignment and "->" in self.assignment:
|
52
|
+
# parse the single arrow
|
53
|
+
ins_outs = self.assignment.split("->", 1)
|
54
|
+
outs_str = ins_outs[1]
|
55
|
+
outs = [x.strip() for x in outs_str.split(",") if x.strip()]
|
56
|
+
if not self.output_fields:
|
57
|
+
self.output_fields = outs
|
58
|
+
return self
|
59
|
+
|
60
|
+
def fill_fields(self, **kwargs) -> None:
|
61
|
+
"""
|
62
|
+
A small helper: fill fields in this form by direct assignment.
|
63
|
+
Usually you'd do 'myform(field=val, field2=val2)', but sometimes you want partial updates.
|
64
|
+
"""
|
65
|
+
for k, v in kwargs.items():
|
66
|
+
setattr(self, k, v)
|
67
|
+
|
68
|
+
def to_instructions(self) -> dict[str, Any]:
|
69
|
+
"""
|
70
|
+
Return a small dictionary that an LLM can read as an 'instruction context'.
|
71
|
+
"""
|
72
|
+
return {
|
73
|
+
"assignment": self.assignment,
|
74
|
+
"flow": (
|
75
|
+
self.flow_definition.model_dump()
|
76
|
+
if self.flow_definition
|
77
|
+
else None
|
78
|
+
),
|
79
|
+
"guidance": self.guidance,
|
80
|
+
"task": self.task,
|
81
|
+
"required_outputs": self.output_fields,
|
82
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# forms/report.py
|
2
|
+
|
3
|
+
from pydantic import Field
|
4
|
+
|
5
|
+
from lionagi.protocols.generic.pile import Pile
|
6
|
+
|
7
|
+
from .base import BaseForm
|
8
|
+
from .form import Form
|
9
|
+
|
10
|
+
|
11
|
+
class Report(BaseForm):
|
12
|
+
"""
|
13
|
+
A minimal class that collects multiple completed forms as "sub-tasks."
|
14
|
+
If you have a single FlowDefinition that describes the entire multi-step pipeline,
|
15
|
+
you can track each step as a separate form in here.
|
16
|
+
"""
|
17
|
+
|
18
|
+
default_form_cls: type[Form] = Form
|
19
|
+
completed_forms: Pile[Form] = Field(
|
20
|
+
default_factory=lambda: Pile(item_type={Form}),
|
21
|
+
description="A list of forms that have been completed for this report.",
|
22
|
+
)
|
23
|
+
form_assignments: dict[str, str] = Field(
|
24
|
+
default_factory=dict,
|
25
|
+
description="Mapping from form ID -> assignment string",
|
26
|
+
)
|
27
|
+
|
28
|
+
def add_completed_form(
|
29
|
+
self, form: Form, update_report_fields: bool = False
|
30
|
+
):
|
31
|
+
"""
|
32
|
+
Add a completed form. Optionally update the report’s fields from the form's output.
|
33
|
+
"""
|
34
|
+
missing = form.check_completeness()
|
35
|
+
if missing:
|
36
|
+
raise ValueError(
|
37
|
+
f"Form {form.id} is incomplete: missing {missing}."
|
38
|
+
)
|
39
|
+
self.completed_forms.append(form)
|
40
|
+
self.form_assignments[form.id] = form.assignment or ""
|
41
|
+
# optionally update the report’s own fields
|
42
|
+
if update_report_fields:
|
43
|
+
for f_ in form.output_fields:
|
44
|
+
val = getattr(form, f_, None)
|
45
|
+
setattr(self, f_, val)
|
@@ -10,6 +10,7 @@ from .action.request_response_model import (
|
|
10
10
|
)
|
11
11
|
from .action.tool import FuncTool, FuncToolRef, Tool, ToolRef
|
12
12
|
from .forms.base import BaseForm
|
13
|
+
from .forms.flow import FlowDefinition, FlowStep
|
13
14
|
from .forms.form import Form
|
14
15
|
from .forms.report import Report
|
15
16
|
from .instruct.base import (
|
@@ -66,4 +67,6 @@ __all__ = (
|
|
66
67
|
"FuncTool",
|
67
68
|
"FuncToolRef",
|
68
69
|
"FunctionCalling",
|
70
|
+
"FlowDefinition",
|
71
|
+
"FlowStep",
|
69
72
|
)
|
@@ -2357,7 +2357,10 @@ def breakdown_pydantic_annotation(
|
|
2357
2357
|
|
2358
2358
|
|
2359
2359
|
def _is_pydantic_model(x: Any) -> bool:
|
2360
|
-
|
2360
|
+
try:
|
2361
|
+
return isclass(x) and issubclass(x, BaseModel)
|
2362
|
+
except TypeError:
|
2363
|
+
return False
|
2361
2364
|
|
2362
2365
|
|
2363
2366
|
def run_package_manager_command(
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.8.0"
|