flowcept 0.9.17__tar.gz → 0.9.19__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.
- {flowcept-0.9.17 → flowcept-0.9.19}/.gitignore +1 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/Makefile +4 -4
- {flowcept-0.9.17 → flowcept-0.9.19}/PKG-INFO +8 -1
- {flowcept-0.9.17 → flowcept-0.9.19}/README.md +1 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/deployment/Dockerfile +2 -5
- flowcept-0.9.19/docs/agent.rst +43 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/index.rst +1 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/prov_capture.rst +1 -1
- {flowcept-0.9.17 → flowcept-0.9.19}/pyproject.toml +11 -3
- {flowcept-0.9.17 → flowcept-0.9.19}/resources/sample_settings.yaml +2 -1
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/agent_client.py +10 -4
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/agents_utils.py +54 -19
- flowcept-0.9.19/src/flowcept/agents/flowcept_agent.py +134 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/flowcept_ctx_manager.py +116 -46
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/gui/gui_utils.py +21 -3
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/prompts/general_prompts.py +1 -1
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/prompts/in_memory_query_prompts.py +158 -45
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/tools/general_tools.py +20 -3
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/tools/in_memory_queries/in_memory_queries_tools.py +14 -31
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/docdb_dao/lmdb_dao.py +48 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/keyvalue_dao.py +12 -3
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/mq_dao/mq_dao_base.py +37 -20
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/mq_dao/mq_dao_kafka.py +2 -2
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/mq_dao/mq_dao_redis.py +33 -2
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/flowcept_dataclasses/task_object.py +4 -1
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/configs.py +17 -3
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowcept_api/flowcept_controller.py +5 -1
- flowcept-0.9.19/src/flowcept/flowceptor/adapters/mlflow/interception_event_handler.py +50 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/mlflow/mlflow_interceptor.py +18 -4
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/tensorboard/tensorboard_interceptor.py +1 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/consumers/agent/base_agent_context_manager.py +9 -10
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/consumers/base_consumer.py +22 -4
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/consumers/document_inserter.py +22 -1
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/instrumentation/flowcept_task.py +147 -51
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/instrumentation/task_capture.py +10 -1
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/version.py +1 -1
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/adapters/test_file_observer.py +4 -1
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/adapters/test_mlflow.py +42 -6
- flowcept-0.9.19/tests/agent/agent_tests.py +95 -0
- flowcept-0.9.19/tests/conftest.py +16 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/instrumentation_tests/flowcept_explicit_tasks.py +43 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/instrumentation_tests/flowcept_task_decorator_test.py +31 -2
- flowcept-0.9.19/tests/misc_tests/__init__.py +0 -0
- flowcept-0.9.17/src/flowcept/agents/flowcept_agent.py +0 -30
- flowcept-0.9.17/src/flowcept/flowceptor/adapters/mlflow/interception_event_handler.py +0 -19
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/checks.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/create-release-n-publish.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/run-llm-tests.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/run-tests-all-dbs.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/run-tests-in-container.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/run-tests-kafka.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/run-tests-py313.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/run-tests-simple.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/run-tests.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/run_examples.sh +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.github/workflows/version_bumper.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/.readthedocs.yaml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/CONTRIBUTING.md +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/LICENSE +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/deployment/compose-grafana.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/deployment/compose-kafka.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/deployment/compose-mofka.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/deployment/compose-mongo.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/deployment/compose.yml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/api-reference.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/architecture.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/cli-reference.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/conf.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/contributing.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/img/PROV-AGENT.svg +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/img/architecture-diagram.png +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/img/flowcept-logo-dark.png +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/img/flowcept-logo.png +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/large_data.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/prov_query.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/prov_storage.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/publications/README.md +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/quick_start.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/schemas.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/setup.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/task_schema.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/telemetry_capture.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/docs/workflow_schema.rst +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/agents/a2a/README.md +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/agents/a2a/agent1.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/agents/a2a/agent2.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/agents/aec_agent_context_manager.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/agents/aec_agent_mock.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/agents/aec_prompts.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/agents/opt_driver_mock.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/consumers/ping_pong_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/consumers/simple_consumer.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/consumers/simple_publisher.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/convergence_loop_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/dask_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/distributed_consumer_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/instrumented_loop_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/instrumented_simple_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_complex/README.md +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_complex/custom_provenance_id_mapping.yaml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_complex/llm_dataprep.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_complex/llm_main_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_complex/llm_model.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_complex/llm_test_runner.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_tutorial/README.md +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_tutorial/analysis.ipynb +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_tutorial/llm_dataprep.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_tutorial/llm_model.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/llm_tutorial/llm_train_campaign.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/mlflow_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/mqtt_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/single_layer_perceptron_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/start_here.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/tensorboard_example.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/unmanaged/main.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/examples/unmanaged/simple_task.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/notebooks/analytics.ipynb +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/notebooks/dask.ipynb +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/notebooks/dask_from_CLI.ipynb +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/notebooks/mlflow.ipynb +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/notebooks/reset_dask_nb_exec_counts.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/notebooks/tensorboard.ipynb +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/resources/mofka/bedrock_setup.sh +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/resources/mofka/consumer.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/resources/mofka/mofka-requirements.yaml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/resources/mofka/mofka_config.json +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/resources/ontology/catalog-v001.xml +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/resources/ontology/prov_agent.owl +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/resources/simple_redis_consumer.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/dynamic_schema_tracker.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/gui/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/gui/agent_gui.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/gui/audio_utils.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/llms/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/llms/claude_gcp.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/llms/gemini25.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/prompts/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/tools/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/tools/in_memory_queries/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/agents/tools/in_memory_queries/pandas_agent_utils.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/analytics/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/analytics/analytics_utils.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/analytics/data_augmentation.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/analytics/plot.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/cli.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/autoflush_buffer.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/docdb_dao/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/docdb_dao/docdb_dao_base.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/docdb_dao/mongodb_dao.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/mq_dao/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/mq_dao/mq_dao_mofka.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/daos/redis_conn.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/flowcept_dataclasses/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/flowcept_dataclasses/base_settings_dataclasses.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/flowcept_dataclasses/telemetry.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/flowcept_dataclasses/workflow_object.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/flowcept_logger.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/query_utils.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/settings_factory.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/task_data_preprocess.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/utils.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/commons/vocabulary.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowcept_api/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowcept_api/db_api.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowcept_api/task_query_api.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowcept_webserver/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowcept_webserver/app.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowcept_webserver/resources/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowcept_webserver/resources/query_rsrc.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowcept_webserver/resources/task_messages_rsrc.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/base_interceptor.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/brokers/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/brokers/mqtt_interceptor.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/dask/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/dask/dask_dataclasses.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/dask/dask_interceptor.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/dask/dask_plugins.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/instrumentation_interceptor.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/interceptor_state_manager.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/mlflow/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/mlflow/mlflow_dao.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/mlflow/mlflow_dataclasses.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/tensorboard/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/adapters/tensorboard/tensorboard_dataclasses.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/consumers/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/consumers/agent/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/consumers/consumer_utils.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/flowceptor/telemetry_capture.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/instrumentation/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/instrumentation/flowcept_agent_task.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/instrumentation/flowcept_decorator.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/instrumentation/flowcept_loop.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/src/flowcept/instrumentation/flowcept_torch.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/adapters/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/adapters/dask_test_utils.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/adapters/test_broker.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/adapters/test_dask.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/adapters/test_dask_with_context_mgmt.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/adapters/test_tensorboard.py +0 -0
- {flowcept-0.9.17/tests/api → flowcept-0.9.19/tests/agent}/__init__.py +0 -0
- {flowcept-0.9.17/tests/doc_db_inserter → flowcept-0.9.19/tests/api}/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/api/db_api_test.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/api/flowcept_api_test.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/api/sample_data.json +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/api/sample_data_with_telemetry_and_rai.json +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/api/task_query_api_test.py +0 -0
- {flowcept-0.9.17/tests/instrumentation_tests → flowcept-0.9.19/tests/doc_db_inserter}/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/doc_db_inserter/doc_db_inserter_test.py +0 -0
- {flowcept-0.9.17/tests/instrumentation_tests/ml_tests → flowcept-0.9.19/tests/instrumentation_tests}/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/instrumentation_tests/flowcept_loop_test.py +0 -0
- {flowcept-0.9.17/tests/misc_tests → flowcept-0.9.19/tests/instrumentation_tests/ml_tests}/__init__.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/instrumentation_tests/ml_tests/dl_trainer.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/instrumentation_tests/ml_tests/ml_decorator_dask_test.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/instrumentation_tests/ml_tests/ml_decorator_test.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/misc_tests/log_test.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/misc_tests/singleton_test.py +0 -0
- {flowcept-0.9.17 → flowcept-0.9.19}/tests/misc_tests/telemetry_test.py +0 -0
|
@@ -77,13 +77,13 @@ run:
|
|
|
77
77
|
docker run --rm -v $(shell pwd):/flowcept -e KVDB_HOST=flowcept_redis -e MQ_HOST=flowcept_redis -e MONGO_HOST=flowcept_mongo --network flowcept_default -it flowcept
|
|
78
78
|
|
|
79
79
|
tests-in-container-mongo:
|
|
80
|
-
docker run --rm -v $(shell pwd):/flowcept -e KVDB_HOST=flowcept_redis -e MQ_HOST=flowcept_redis -e MONGO_HOST=flowcept_mongo -e MONGO_ENABLED=true -e LMDB_ENABLED=false --network flowcept_default flowcept /opt/conda/envs/flowcept/bin/pytest --ignore=tests/instrumentation_tests/ml_tests
|
|
80
|
+
docker run --rm -v $(shell pwd):/flowcept -e KVDB_HOST=flowcept_redis -e MQ_HOST=flowcept_redis -e MONGO_HOST=flowcept_mongo -e MONGO_ENABLED=true -e LMDB_ENABLED=false --network flowcept_default flowcept /opt/conda/envs/flowcept/bin/pytest tests --ignore=tests/instrumentation_tests/ml_tests
|
|
81
81
|
|
|
82
82
|
tests-in-container:
|
|
83
|
-
docker run --rm -v $(shell pwd):/flowcept -e KVDB_HOST=flowcept_redis -e MQ_HOST=flowcept_redis -e MONGO_ENABLED=false -e LMDB_ENABLED=true --network flowcept_default flowcept /opt/conda/envs/flowcept/bin/pytest --ignore=tests/instrumentation_tests/ml_tests
|
|
83
|
+
docker run --rm -v $(shell pwd):/flowcept -e KVDB_HOST=flowcept_redis -e MQ_HOST=flowcept_redis -e MONGO_ENABLED=false -e LMDB_ENABLED=true --network flowcept_default flowcept /opt/conda/envs/flowcept/bin/pytest tests --ignore=tests/instrumentation_tests/ml_tests
|
|
84
84
|
|
|
85
85
|
tests-in-container-kafka:
|
|
86
|
-
docker run --rm -v $(shell pwd):/flowcept -e KVDB_HOST=flowcept_redis -e MQ_HOST=kafka -e MONGO_HOST=flowcept_mongo -e MQ_PORT=29092 -e MQ_TYPE=kafka -e MONGO_ENABLED=true -e LMDB_ENABLED=false --network flowcept_default flowcept /opt/conda/envs/flowcept/bin/pytest --ignore=tests/instrumentation_tests/ml_tests
|
|
86
|
+
docker run --rm -v $(shell pwd):/flowcept -e KVDB_HOST=flowcept_redis -e MQ_HOST=kafka -e MONGO_HOST=flowcept_mongo -e MQ_PORT=29092 -e MQ_TYPE=kafka -e MONGO_ENABLED=true -e LMDB_ENABLED=false --network flowcept_default flowcept /opt/conda/envs/flowcept/bin/pytest tests --ignore=tests/instrumentation_tests/ml_tests
|
|
87
87
|
|
|
88
88
|
# This command can be removed once we have our CLI
|
|
89
89
|
liveness:
|
|
@@ -115,7 +115,7 @@ services-stop-mofka:
|
|
|
115
115
|
# Run unit tests using pytest
|
|
116
116
|
.PHONY: tests
|
|
117
117
|
tests:
|
|
118
|
-
pytest --ignore=tests/adapters/test_tensorboard.py
|
|
118
|
+
pytest --timeout=300 --ignore=tests/adapters/test_tensorboard.py
|
|
119
119
|
|
|
120
120
|
.PHONY: tests-notebooks
|
|
121
121
|
tests-notebooks:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flowcept
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.19
|
|
4
4
|
Summary: Capture and query workflow provenance data using data observability
|
|
5
5
|
Author: Oak Ridge National Laboratory
|
|
6
6
|
License-Expression: MIT
|
|
@@ -41,6 +41,7 @@ Requires-Dist: pyarrow; extra == 'all'
|
|
|
41
41
|
Requires-Dist: pymongo; extra == 'all'
|
|
42
42
|
Requires-Dist: pymupdf; extra == 'all'
|
|
43
43
|
Requires-Dist: pytest; extra == 'all'
|
|
44
|
+
Requires-Dist: pytest-timeout; extra == 'all'
|
|
44
45
|
Requires-Dist: pyyaml; extra == 'all'
|
|
45
46
|
Requires-Dist: redis; extra == 'all'
|
|
46
47
|
Requires-Dist: requests; extra == 'all'
|
|
@@ -50,6 +51,7 @@ Requires-Dist: seaborn; extra == 'all'
|
|
|
50
51
|
Requires-Dist: sphinx; extra == 'all'
|
|
51
52
|
Requires-Dist: sqlalchemy; extra == 'all'
|
|
52
53
|
Requires-Dist: streamlit; extra == 'all'
|
|
54
|
+
Requires-Dist: tabulate; extra == 'all'
|
|
53
55
|
Requires-Dist: tbparse; extra == 'all'
|
|
54
56
|
Requires-Dist: tensorboard; extra == 'all'
|
|
55
57
|
Requires-Dist: tensorflow; extra == 'all'
|
|
@@ -69,6 +71,7 @@ Requires-Dist: jupyterlab; extra == 'dev'
|
|
|
69
71
|
Requires-Dist: nbmake; extra == 'dev'
|
|
70
72
|
Requires-Dist: pika; extra == 'dev'
|
|
71
73
|
Requires-Dist: pytest; extra == 'dev'
|
|
74
|
+
Requires-Dist: pytest-timeout; extra == 'dev'
|
|
72
75
|
Requires-Dist: pyyaml; extra == 'dev'
|
|
73
76
|
Requires-Dist: ruff; extra == 'dev'
|
|
74
77
|
Requires-Dist: sphinx; extra == 'dev'
|
|
@@ -94,6 +97,7 @@ Requires-Dist: matplotlib; extra == 'llm-agent'
|
|
|
94
97
|
Requires-Dist: mcp[cli]; extra == 'llm-agent'
|
|
95
98
|
Requires-Dist: pymupdf; extra == 'llm-agent'
|
|
96
99
|
Requires-Dist: streamlit; extra == 'llm-agent'
|
|
100
|
+
Requires-Dist: tabulate; extra == 'llm-agent'
|
|
97
101
|
Provides-Extra: llm-agent-audio
|
|
98
102
|
Requires-Dist: gtts; extra == 'llm-agent-audio'
|
|
99
103
|
Requires-Dist: langchain-community; extra == 'llm-agent-audio'
|
|
@@ -105,6 +109,7 @@ Requires-Dist: pymupdf; extra == 'llm-agent-audio'
|
|
|
105
109
|
Requires-Dist: speechrecognition; extra == 'llm-agent-audio'
|
|
106
110
|
Requires-Dist: streamlit; extra == 'llm-agent-audio'
|
|
107
111
|
Requires-Dist: streamlit-mic-recorder; extra == 'llm-agent-audio'
|
|
112
|
+
Requires-Dist: tabulate; extra == 'llm-agent-audio'
|
|
108
113
|
Provides-Extra: llm-google
|
|
109
114
|
Requires-Dist: google-genai; extra == 'llm-google'
|
|
110
115
|
Requires-Dist: langchain-community; extra == 'llm-google'
|
|
@@ -113,6 +118,7 @@ Requires-Dist: matplotlib; extra == 'llm-google'
|
|
|
113
118
|
Requires-Dist: mcp[cli]; extra == 'llm-google'
|
|
114
119
|
Requires-Dist: pymupdf; extra == 'llm-google'
|
|
115
120
|
Requires-Dist: streamlit; extra == 'llm-google'
|
|
121
|
+
Requires-Dist: tabulate; extra == 'llm-google'
|
|
116
122
|
Provides-Extra: lmdb
|
|
117
123
|
Requires-Dist: lmdb; extra == 'lmdb'
|
|
118
124
|
Provides-Extra: ml-dev
|
|
@@ -180,6 +186,7 @@ Flowcept captures and queries workflow provenance at runtime with minimal code c
|
|
|
180
186
|
|
|
181
187
|
|
|
182
188
|
<h4 align="center">
|
|
189
|
+
<a href="https://flowcept.org">Website</a> •
|
|
183
190
|
<a href="https://flowcept.readthedocs.io/">Documentation</a> •
|
|
184
191
|
<a href="./docs/publications">Publications</a>
|
|
185
192
|
</h4>
|
|
@@ -31,6 +31,7 @@ Flowcept captures and queries workflow provenance at runtime with minimal code c
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
<h4 align="center">
|
|
34
|
+
<a href="https://flowcept.org">Website</a> •
|
|
34
35
|
<a href="https://flowcept.readthedocs.io/">Documentation</a> •
|
|
35
36
|
<a href="./docs/publications">Publications</a>
|
|
36
37
|
</h4>
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# Use the command `make build` to build this image.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
RUN apt-get update && \
|
|
5
|
-
apt-get install -y vim curl wget make patch gcc \
|
|
6
|
-
&& rm -rf /var/lib/apt/lists/*
|
|
2
|
+
# Use conda-forge base image consistently across local/CI.
|
|
3
|
+
FROM condaforge/miniforge3:23.11.0-0
|
|
7
4
|
|
|
8
5
|
WORKDIR /flowcept
|
|
9
6
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Flowcept Agent
|
|
2
|
+
==============
|
|
3
|
+
|
|
4
|
+
The Flowcept Agent is an MCP-powered LLM interface for querying provenance data. It exposes a small set of tools
|
|
5
|
+
(e.g., ``prompt_handler``) that route natural-language questions to in-memory queries over captured task summaries.
|
|
6
|
+
|
|
7
|
+
Online-first design
|
|
8
|
+
------------------
|
|
9
|
+
Like Flowcept as a whole, the agent is designed to run **while a workflow is still executing**. In online mode,
|
|
10
|
+
it consumes messages from the MQ (typically Redis) so it can respond to queries in near real time. This is the
|
|
11
|
+
recommended setup for interactive RAG/MCP analysis during live runs.
|
|
12
|
+
|
|
13
|
+
Offline (file-based) queries
|
|
14
|
+
----------------------------
|
|
15
|
+
For simple tests or disconnected environments, the agent can also be initialized from a **JSONL buffer file**.
|
|
16
|
+
In this mode, Flowcept writes messages to disk (``dump_buffer``), and the agent loads the file once at startup
|
|
17
|
+
before serving queries.
|
|
18
|
+
|
|
19
|
+
This is a minimal offline example:
|
|
20
|
+
|
|
21
|
+
.. code-block:: python
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
from flowcept import Flowcept, flowcept_task
|
|
25
|
+
from flowcept.agents.flowcept_agent import FlowceptAgent
|
|
26
|
+
|
|
27
|
+
@flowcept_task
|
|
28
|
+
def sum_one(x):
|
|
29
|
+
return x + 1
|
|
30
|
+
|
|
31
|
+
# Run a small workflow and dump the buffer to disk
|
|
32
|
+
with Flowcept(start_persistence=False, save_workflow=False, check_safe_stops=False) as f:
|
|
33
|
+
sum_one(1)
|
|
34
|
+
f.dump_buffer("flowcept_buffer.jsonl")
|
|
35
|
+
|
|
36
|
+
# Start the agent from the buffer file and query it
|
|
37
|
+
agent = FlowceptAgent(buffer_path="flowcept_buffer.jsonl")
|
|
38
|
+
agent.start()
|
|
39
|
+
resp = agent.query("how many tasks?")
|
|
40
|
+
print(json.loads(resp))
|
|
41
|
+
agent.stop()
|
|
42
|
+
|
|
43
|
+
In the future, this page will include a full **online** example (live MQ + Redis) and deployment guidance.
|
|
@@ -124,7 +124,7 @@ Optional Arguments
|
|
|
124
124
|
|
|
125
125
|
When creating a ``Flowcept`` instance (with or without a context manager), you can pass:
|
|
126
126
|
|
|
127
|
-
- **interceptors**: list of interceptors (e.g., ``"instrumentation"``, ``"dask"``, ``"mlflow"``). Defaults to ``["instrumentation"]`` if enabled.
|
|
127
|
+
- **interceptors**: list of interceptors (e.g., ``"instrumentation"``, ``"dask"``, ``"mlflow"``). Defaults to ``["instrumentation"]`` if enabled. Instrumentation defaults to enabled unless explicitly set to ``false`` in settings.
|
|
128
128
|
- **bundle_exec_id**: identifier for grouping interceptors. Defaults to ``id(self)``.
|
|
129
129
|
- **campaign_id**: unique identifier for the campaign. Defaults to a generated UUID.
|
|
130
130
|
- **workflow_id**: unique identifier for the workflow. Defaults to a generated UUID.
|
|
@@ -65,7 +65,7 @@ mlflow = ["mlflow-skinny", "SQLAlchemy", "alembic", "watchdog", "cryptography"]
|
|
|
65
65
|
nvidia = ["nvidia-ml-py"]
|
|
66
66
|
mqtt = ["paho-mqtt"]
|
|
67
67
|
tensorboard = ["tensorboard", "tensorflow", "tbparse"]
|
|
68
|
-
llm_agent = ["mcp[cli]", "langchain_community", "langchain_openai", "streamlit", "PyMuPDF", "matplotlib"]
|
|
68
|
+
llm_agent = ["mcp[cli]", "langchain_community", "langchain_openai", "streamlit", "PyMuPDF", "matplotlib", "tabulate"]
|
|
69
69
|
llm_google = ["flowcept[llm_agent]", "google-genai"]
|
|
70
70
|
llm_agent_audio = ["flowcept[llm_agent]", "streamlit-mic-recorder", "SpeechRecognition", "pydub", "gTTS"]
|
|
71
71
|
# System dependency (required for pydub)
|
|
@@ -80,8 +80,9 @@ dev = [
|
|
|
80
80
|
"nbmake",
|
|
81
81
|
"pika",
|
|
82
82
|
"pytest",
|
|
83
|
+
"pytest-timeout",
|
|
83
84
|
"ruff",
|
|
84
|
-
"pyyaml"
|
|
85
|
+
"pyyaml"
|
|
85
86
|
]
|
|
86
87
|
# Torch and some other ml-specific libs, only used for dev purposes, require the following specific versions.
|
|
87
88
|
ml_dev = [
|
|
@@ -129,5 +130,12 @@ packages = ["src/flowcept"]
|
|
|
129
130
|
[tool.hatch.build.targets.wheel.force-include]
|
|
130
131
|
"resources/sample_settings.yaml" = "resources/sample_settings.yaml"
|
|
131
132
|
|
|
133
|
+
[tool.pytest.ini_options]
|
|
134
|
+
filterwarnings = [
|
|
135
|
+
"ignore:websockets\\.legacy is deprecated:DeprecationWarning",
|
|
136
|
+
"ignore:websockets\\.server\\.WebSocketServerProtocol is deprecated:DeprecationWarning",
|
|
137
|
+
"ignore:Use `streamable_http_client` instead\\.:DeprecationWarning",
|
|
138
|
+
]
|
|
139
|
+
|
|
132
140
|
[project.scripts]
|
|
133
|
-
flowcept = "flowcept.cli:main"
|
|
141
|
+
flowcept = "flowcept.cli:main"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
flowcept_version: 0.9.
|
|
1
|
+
flowcept_version: 0.9.19 # Version of the Flowcept package. This setting file is compatible with this version.
|
|
2
2
|
|
|
3
3
|
project:
|
|
4
4
|
debug: true # Toggle debug mode. This will add a property `debug: true` to all saved data, making it easier to retrieve/delete them later.
|
|
@@ -94,6 +94,7 @@ agent:
|
|
|
94
94
|
service_provider: '?'
|
|
95
95
|
model_kwargs: {}
|
|
96
96
|
audio_enabled: false
|
|
97
|
+
debug: true
|
|
97
98
|
|
|
98
99
|
databases:
|
|
99
100
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
2
4
|
from typing import Dict, List, Callable
|
|
3
5
|
|
|
4
6
|
from flowcept.configs import AGENT_HOST, AGENT_PORT
|
|
@@ -48,10 +50,14 @@ def run_tool(
|
|
|
48
50
|
result: List[TextContent] = await session.call_tool(tool_name, arguments=kwargs)
|
|
49
51
|
actual_result = []
|
|
50
52
|
for r in result.content:
|
|
51
|
-
if isinstance(r, str)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
actual_result.append(
|
|
53
|
+
text = r if isinstance(r, str) else r.text
|
|
54
|
+
try:
|
|
55
|
+
json.loads(text)
|
|
56
|
+
actual_result.append(text)
|
|
57
|
+
except Exception:
|
|
58
|
+
match = re.search(r"Error code:\\s*(\\d+)", text)
|
|
59
|
+
code = int(match.group(1)) if match else 400
|
|
60
|
+
actual_result.append(json.dumps({"code": code, "result": text, "tool_name": tool_name}))
|
|
55
61
|
|
|
56
62
|
return actual_result
|
|
57
63
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import re
|
|
3
|
+
import unicodedata
|
|
2
4
|
from typing import Union, Dict
|
|
3
5
|
|
|
4
6
|
from flowcept.flowceptor.consumers.agent.base_agent_context_manager import BaseAgentContextManager
|
|
@@ -137,8 +139,8 @@ def build_llm_model(
|
|
|
137
139
|
if _service_provider == "sambanova":
|
|
138
140
|
from langchain_community.llms.sambanova import SambaStudio
|
|
139
141
|
|
|
140
|
-
os.environ["SAMBASTUDIO_URL"] = AGENT.get("llm_server_url")
|
|
141
|
-
os.environ["SAMBASTUDIO_API_KEY"] = AGENT.get("api_key")
|
|
142
|
+
os.environ["SAMBASTUDIO_URL"] = os.environ.get("SAMBASTUDIO_URL", AGENT.get("llm_server_url"))
|
|
143
|
+
os.environ["SAMBASTUDIO_API_KEY"] = os.environ.get("SAMBASTUDIO_API_KEY", AGENT.get("api_key"))
|
|
142
144
|
|
|
143
145
|
llm = SambaStudio(model_kwargs=_model_kwargs)
|
|
144
146
|
elif _service_provider == "azure":
|
|
@@ -153,7 +155,16 @@ def build_llm_model(
|
|
|
153
155
|
from langchain_openai import ChatOpenAI
|
|
154
156
|
|
|
155
157
|
api_key = os.environ.get("OPENAI_API_KEY", AGENT.get("api_key", None))
|
|
156
|
-
|
|
158
|
+
base_url = os.environ.get("OPENAI_BASE_URL", AGENT.get("llm_server_url") or None)
|
|
159
|
+
org = os.environ.get("OPENAI_ORG_ID", AGENT.get("organization", None))
|
|
160
|
+
|
|
161
|
+
init_kwargs = {"api_key": api_key}
|
|
162
|
+
if base_url:
|
|
163
|
+
init_kwargs["base_url"] = base_url
|
|
164
|
+
if org:
|
|
165
|
+
init_kwargs["organization"] = org
|
|
166
|
+
|
|
167
|
+
llm = ChatOpenAI(**init_kwargs, **_model_kwargs)
|
|
157
168
|
elif _service_provider == "google":
|
|
158
169
|
if "claude" in _model_kwargs["model"]:
|
|
159
170
|
api_key = os.environ.get("GOOGLE_API_KEY", AGENT.get("api_key", None))
|
|
@@ -166,22 +177,6 @@ def build_llm_model(
|
|
|
166
177
|
from flowcept.agents.llms.gemini25 import Gemini25LLM
|
|
167
178
|
|
|
168
179
|
llm = Gemini25LLM(**_model_kwargs)
|
|
169
|
-
elif _service_provider == "openai":
|
|
170
|
-
from langchain_openai import ChatOpenAI
|
|
171
|
-
|
|
172
|
-
api_key = os.environ.get("OPENAI_API_KEY", AGENT.get("api_key"))
|
|
173
|
-
base_url = os.environ.get("OPENAI_BASE_URL", AGENT.get("llm_server_url") or None) # optional
|
|
174
|
-
org = os.environ.get("OPENAI_ORG_ID", AGENT.get("organization", None)) # optional
|
|
175
|
-
|
|
176
|
-
init_kwargs = {"api_key": api_key}
|
|
177
|
-
if base_url:
|
|
178
|
-
init_kwargs["base_url"] = base_url
|
|
179
|
-
if org:
|
|
180
|
-
init_kwargs["organization"] = org
|
|
181
|
-
|
|
182
|
-
# IMPORTANT: use the merged kwargs so `model` and temps flow through
|
|
183
|
-
llm = ChatOpenAI(**init_kwargs, **_model_kwargs)
|
|
184
|
-
|
|
185
180
|
else:
|
|
186
181
|
raise Exception("Currently supported providers are sambanova, openai, azure, and google.")
|
|
187
182
|
if track_tools:
|
|
@@ -194,3 +189,43 @@ def build_llm_model(
|
|
|
194
189
|
if tool_task:
|
|
195
190
|
llm.parent_task_id = tool_task.task_id
|
|
196
191
|
return llm
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def normalize_message(user_msg: str) -> str:
|
|
195
|
+
"""
|
|
196
|
+
Normalize a user message into a canonical, comparison-friendly form.
|
|
197
|
+
|
|
198
|
+
The function standardizes text by trimming whitespace, applying Unicode
|
|
199
|
+
normalization, normalizing dash characters, collapsing repeated whitespace,
|
|
200
|
+
removing trailing punctuation that does not affect semantics, and converting
|
|
201
|
+
the result to lowercase.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
user_msg : str
|
|
206
|
+
Raw user input message.
|
|
207
|
+
|
|
208
|
+
Returns
|
|
209
|
+
-------
|
|
210
|
+
str
|
|
211
|
+
Normalized message suitable for matching, comparison, or hashing.
|
|
212
|
+
"""
|
|
213
|
+
# 1) Strip leading/trailing whitespace
|
|
214
|
+
user_msg = user_msg.strip()
|
|
215
|
+
|
|
216
|
+
# 2) Unicode normalize to avoid weird characters (like fancy quotes, dashes)
|
|
217
|
+
user_msg = unicodedata.normalize("NFKC", user_msg)
|
|
218
|
+
|
|
219
|
+
# 3) Normalize dashes commonly used in chemistry (C–H, C—H, etc.)
|
|
220
|
+
user_msg = user_msg.replace("–", "-").replace("—", "-")
|
|
221
|
+
|
|
222
|
+
# 4) Collapse multiple spaces / newlines into a single space
|
|
223
|
+
user_msg = re.sub(r"\s+", " ", user_msg)
|
|
224
|
+
|
|
225
|
+
# 5) Remove trailing punctuation that doesn't change semantics
|
|
226
|
+
# e.g., "?", "!", "." at the VERY end
|
|
227
|
+
user_msg = re.sub(r"[?!.\s]+$", "", user_msg)
|
|
228
|
+
|
|
229
|
+
user_msg = user_msg.lower()
|
|
230
|
+
|
|
231
|
+
return user_msg
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from threading import Thread
|
|
4
|
+
|
|
5
|
+
from flowcept.agents import check_liveness
|
|
6
|
+
from flowcept.agents.agents_utils import ToolResult
|
|
7
|
+
from flowcept.agents.tools.general_tools import prompt_handler
|
|
8
|
+
from flowcept.agents.agent_client import run_tool
|
|
9
|
+
from flowcept.agents.flowcept_ctx_manager import mcp_flowcept, ctx_manager
|
|
10
|
+
from flowcept.commons.flowcept_logger import FlowceptLogger
|
|
11
|
+
from flowcept.configs import AGENT_HOST, AGENT_PORT, DUMP_BUFFER_PATH, MQ_ENABLED
|
|
12
|
+
from flowcept.flowceptor.consumers.agent.base_agent_context_manager import BaseAgentContextManager
|
|
13
|
+
from uuid import uuid4
|
|
14
|
+
|
|
15
|
+
import uvicorn
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FlowceptAgent:
|
|
19
|
+
"""
|
|
20
|
+
Flowcept agent server wrapper with optional offline buffer loading.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, buffer_path: str | None = None):
|
|
24
|
+
"""
|
|
25
|
+
Initialize a FlowceptAgent.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
buffer_path : str or None
|
|
30
|
+
Optional path to a JSONL buffer file. When MQ is disabled, the agent
|
|
31
|
+
loads this file once at startup.
|
|
32
|
+
"""
|
|
33
|
+
self.buffer_path = buffer_path
|
|
34
|
+
self.logger = FlowceptLogger()
|
|
35
|
+
self._server_thread: Thread | None = None
|
|
36
|
+
self._server = None
|
|
37
|
+
|
|
38
|
+
def _load_buffer_once(self) -> int:
|
|
39
|
+
"""
|
|
40
|
+
Load messages from a JSONL buffer file into the agent context.
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
int
|
|
45
|
+
Number of messages loaded.
|
|
46
|
+
"""
|
|
47
|
+
path = self.buffer_path or DUMP_BUFFER_PATH
|
|
48
|
+
if not os.path.exists(path):
|
|
49
|
+
raise FileNotFoundError(f"Buffer file not found: {path}")
|
|
50
|
+
|
|
51
|
+
count = 0
|
|
52
|
+
self.logger.info(f"Loading agent buffer from {path}")
|
|
53
|
+
if ctx_manager.agent_id is None:
|
|
54
|
+
agent_id = str(uuid4())
|
|
55
|
+
BaseAgentContextManager.agent_id = agent_id
|
|
56
|
+
ctx_manager.agent_id = agent_id
|
|
57
|
+
with open(path, "r") as handle:
|
|
58
|
+
for line in handle:
|
|
59
|
+
line = line.strip()
|
|
60
|
+
if not line:
|
|
61
|
+
continue
|
|
62
|
+
msg_obj = json.loads(line)
|
|
63
|
+
ctx_manager.message_handler(msg_obj)
|
|
64
|
+
count += 1
|
|
65
|
+
self.logger.info(f"Loaded {count} messages from buffer.")
|
|
66
|
+
return count
|
|
67
|
+
|
|
68
|
+
def _run_server(self):
|
|
69
|
+
"""Run the MCP server (blocking call)."""
|
|
70
|
+
config = uvicorn.Config(mcp_flowcept.streamable_http_app, host=AGENT_HOST, port=AGENT_PORT, lifespan="on")
|
|
71
|
+
self._server = uvicorn.Server(config)
|
|
72
|
+
self._server.run()
|
|
73
|
+
|
|
74
|
+
def start(self):
|
|
75
|
+
"""
|
|
76
|
+
Start the agent server in a background thread.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
FlowceptAgent
|
|
81
|
+
The current instance.
|
|
82
|
+
"""
|
|
83
|
+
if not MQ_ENABLED:
|
|
84
|
+
self._load_buffer_once()
|
|
85
|
+
|
|
86
|
+
self._server_thread = Thread(target=self._run_server, daemon=False)
|
|
87
|
+
self._server_thread.start()
|
|
88
|
+
self.logger.info(f"Flowcept agent server started on {AGENT_HOST}:{AGENT_PORT}")
|
|
89
|
+
return self
|
|
90
|
+
|
|
91
|
+
def stop(self):
|
|
92
|
+
"""Stop the agent server and wait briefly for shutdown."""
|
|
93
|
+
if self._server is not None:
|
|
94
|
+
self._server.should_exit = True
|
|
95
|
+
if self._server_thread is not None:
|
|
96
|
+
self._server_thread.join(timeout=5)
|
|
97
|
+
|
|
98
|
+
def wait(self):
|
|
99
|
+
"""Block until the server thread exits."""
|
|
100
|
+
if self._server_thread is not None:
|
|
101
|
+
self._server_thread.join()
|
|
102
|
+
|
|
103
|
+
def query(self, message: str) -> ToolResult:
|
|
104
|
+
"""
|
|
105
|
+
Send a prompt to the agent's main router tool and return the response.
|
|
106
|
+
"""
|
|
107
|
+
try:
|
|
108
|
+
resp = run_tool(tool_name=prompt_handler, kwargs={"message": message})[0]
|
|
109
|
+
except Exception as e:
|
|
110
|
+
return ToolResult(code=400, result=f"Error executing tool prompt_handler: {e}", tool_name="prompt_handler")
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
return ToolResult(**json.loads(resp))
|
|
114
|
+
except Exception as e:
|
|
115
|
+
return ToolResult(
|
|
116
|
+
code=499,
|
|
117
|
+
result=f"Could not parse tool response as JSON: {resp}",
|
|
118
|
+
extra=str(e),
|
|
119
|
+
tool_name="prompt_handler",
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def main():
|
|
124
|
+
"""
|
|
125
|
+
Start the MCP server.
|
|
126
|
+
"""
|
|
127
|
+
agent = FlowceptAgent().start()
|
|
128
|
+
# Wake up tool call
|
|
129
|
+
print(run_tool(check_liveness, host=AGENT_HOST, port=AGENT_PORT)[0])
|
|
130
|
+
agent.wait()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
main()
|