flock-core 0.5.0b28__py3-none-any.whl → 0.5.56b0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flock-core might be problematic. Click here for more details.
- flock/__init__.py +12 -217
- flock/agent.py +678 -0
- flock/api/themes.py +71 -0
- flock/artifacts.py +79 -0
- flock/cli.py +75 -0
- flock/components.py +173 -0
- flock/dashboard/__init__.py +28 -0
- flock/dashboard/collector.py +283 -0
- flock/dashboard/events.py +182 -0
- flock/dashboard/launcher.py +230 -0
- flock/dashboard/service.py +537 -0
- flock/dashboard/websocket.py +235 -0
- flock/engines/__init__.py +6 -0
- flock/engines/dspy_engine.py +856 -0
- flock/examples.py +128 -0
- flock/{core/util → helper}/cli_helper.py +4 -3
- flock/{core/logging → logging}/__init__.py +2 -3
- flock/{core/logging → logging}/formatters/enum_builder.py +3 -4
- flock/{core/logging → logging}/formatters/theme_builder.py +19 -44
- flock/{core/logging → logging}/formatters/themed_formatter.py +69 -115
- flock/{core/logging → logging}/logging.py +77 -61
- flock/{core/logging → logging}/telemetry.py +20 -26
- flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
- flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +6 -9
- flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
- flock/{core/logging → logging}/trace_and_logged.py +20 -24
- flock/mcp/__init__.py +91 -0
- flock/{core/mcp/mcp_client.py → mcp/client.py} +103 -154
- flock/{core/mcp/mcp_config.py → mcp/config.py} +62 -117
- flock/mcp/manager.py +255 -0
- flock/mcp/servers/sse/__init__.py +1 -1
- flock/mcp/servers/sse/flock_sse_server.py +11 -53
- flock/mcp/servers/stdio/__init__.py +1 -1
- flock/mcp/servers/stdio/flock_stdio_server.py +8 -48
- flock/mcp/servers/streamable_http/flock_streamable_http_server.py +17 -62
- flock/mcp/servers/websockets/flock_websocket_server.py +7 -40
- flock/{core/mcp/flock_mcp_tool.py → mcp/tool.py} +16 -26
- flock/mcp/types/__init__.py +42 -0
- flock/{core/mcp → mcp}/types/callbacks.py +9 -15
- flock/{core/mcp → mcp}/types/factories.py +7 -6
- flock/{core/mcp → mcp}/types/handlers.py +13 -18
- flock/{core/mcp → mcp}/types/types.py +70 -74
- flock/{core/mcp → mcp}/util/helpers.py +1 -1
- flock/orchestrator.py +645 -0
- flock/registry.py +148 -0
- flock/runtime.py +262 -0
- flock/service.py +140 -0
- flock/store.py +69 -0
- flock/subscription.py +111 -0
- flock/themes/andromeda.toml +1 -1
- flock/themes/apple-system-colors.toml +1 -1
- flock/themes/arcoiris.toml +1 -1
- flock/themes/atomonelight.toml +1 -1
- flock/themes/ayu copy.toml +1 -1
- flock/themes/ayu-light.toml +1 -1
- flock/themes/belafonte-day.toml +1 -1
- flock/themes/belafonte-night.toml +1 -1
- flock/themes/blulocodark.toml +1 -1
- flock/themes/breeze.toml +1 -1
- flock/themes/broadcast.toml +1 -1
- flock/themes/brogrammer.toml +1 -1
- flock/themes/builtin-dark.toml +1 -1
- flock/themes/builtin-pastel-dark.toml +1 -1
- flock/themes/catppuccin-latte.toml +1 -1
- flock/themes/catppuccin-macchiato.toml +1 -1
- flock/themes/catppuccin-mocha.toml +1 -1
- flock/themes/cga.toml +1 -1
- flock/themes/chalk.toml +1 -1
- flock/themes/ciapre.toml +1 -1
- flock/themes/coffee-theme.toml +1 -1
- flock/themes/cyberpunkscarletprotocol.toml +1 -1
- flock/themes/dark+.toml +1 -1
- flock/themes/darkermatrix.toml +1 -1
- flock/themes/darkside.toml +1 -1
- flock/themes/desert.toml +1 -1
- flock/themes/django.toml +1 -1
- flock/themes/djangosmooth.toml +1 -1
- flock/themes/doomone.toml +1 -1
- flock/themes/dotgov.toml +1 -1
- flock/themes/dracula+.toml +1 -1
- flock/themes/duckbones.toml +1 -1
- flock/themes/encom.toml +1 -1
- flock/themes/espresso.toml +1 -1
- flock/themes/everblush.toml +1 -1
- flock/themes/fairyfloss.toml +1 -1
- flock/themes/fideloper.toml +1 -1
- flock/themes/fishtank.toml +1 -1
- flock/themes/flexoki-light.toml +1 -1
- flock/themes/floraverse.toml +1 -1
- flock/themes/framer.toml +1 -1
- flock/themes/galizur.toml +1 -1
- flock/themes/github.toml +1 -1
- flock/themes/grass.toml +1 -1
- flock/themes/grey-green.toml +1 -1
- flock/themes/gruvboxlight.toml +1 -1
- flock/themes/guezwhoz.toml +1 -1
- flock/themes/harper.toml +1 -1
- flock/themes/hax0r-blue.toml +1 -1
- flock/themes/hopscotch.256.toml +1 -1
- flock/themes/ic-green-ppl.toml +1 -1
- flock/themes/iceberg-dark.toml +1 -1
- flock/themes/japanesque.toml +1 -1
- flock/themes/jubi.toml +1 -1
- flock/themes/kibble.toml +1 -1
- flock/themes/kolorit.toml +1 -1
- flock/themes/kurokula.toml +1 -1
- flock/themes/materialdesigncolors.toml +1 -1
- flock/themes/matrix.toml +1 -1
- flock/themes/mellifluous.toml +1 -1
- flock/themes/midnight-in-mojave.toml +1 -1
- flock/themes/monokai-remastered.toml +1 -1
- flock/themes/monokai-soda.toml +1 -1
- flock/themes/neon.toml +1 -1
- flock/themes/neopolitan.toml +1 -1
- flock/themes/nord-light.toml +1 -1
- flock/themes/ocean.toml +1 -1
- flock/themes/onehalfdark.toml +1 -1
- flock/themes/onehalflight.toml +1 -1
- flock/themes/palenighthc.toml +1 -1
- flock/themes/paulmillr.toml +1 -1
- flock/themes/pencildark.toml +1 -1
- flock/themes/pnevma.toml +1 -1
- flock/themes/purple-rain.toml +1 -1
- flock/themes/purplepeter.toml +1 -1
- flock/themes/raycast-dark.toml +1 -1
- flock/themes/red-sands.toml +1 -1
- flock/themes/relaxed.toml +1 -1
- flock/themes/retro.toml +1 -1
- flock/themes/rose-pine.toml +1 -1
- flock/themes/royal.toml +1 -1
- flock/themes/ryuuko.toml +1 -1
- flock/themes/sakura.toml +1 -1
- flock/themes/scarlet-protocol.toml +1 -1
- flock/themes/seoulbones-dark.toml +1 -1
- flock/themes/shades-of-purple.toml +1 -1
- flock/themes/smyck.toml +1 -1
- flock/themes/softserver.toml +1 -1
- flock/themes/solarized-darcula.toml +1 -1
- flock/themes/square.toml +1 -1
- flock/themes/sugarplum.toml +1 -1
- flock/themes/thayer-bright.toml +1 -1
- flock/themes/tokyonight.toml +1 -1
- flock/themes/tomorrow.toml +1 -1
- flock/themes/ubuntu.toml +1 -1
- flock/themes/ultradark.toml +1 -1
- flock/themes/ultraviolent.toml +1 -1
- flock/themes/unikitty.toml +1 -1
- flock/themes/urple.toml +1 -1
- flock/themes/vesper.toml +1 -1
- flock/themes/vimbones.toml +1 -1
- flock/themes/wildcherry.toml +1 -1
- flock/themes/wilmersdorf.toml +1 -1
- flock/themes/wryan.toml +1 -1
- flock/themes/xcodedarkhc.toml +1 -1
- flock/themes/xcodelight.toml +1 -1
- flock/themes/zenbones-light.toml +1 -1
- flock/themes/zenwritten-dark.toml +1 -1
- flock/utilities.py +301 -0
- flock/{components/utility → utility}/output_utility_component.py +68 -53
- flock/visibility.py +107 -0
- flock_core-0.5.56b0.dist-info/METADATA +747 -0
- flock_core-0.5.56b0.dist-info/RECORD +398 -0
- flock_core-0.5.56b0.dist-info/entry_points.txt +2 -0
- {flock_core-0.5.0b28.dist-info → flock_core-0.5.56b0.dist-info}/licenses/LICENSE +1 -1
- flock/adapter/__init__.py +0 -14
- flock/adapter/azure_adapter.py +0 -68
- flock/adapter/chroma_adapter.py +0 -73
- flock/adapter/faiss_adapter.py +0 -97
- flock/adapter/pinecone_adapter.py +0 -51
- flock/adapter/vector_base.py +0 -47
- flock/cli/assets/release_notes.md +0 -140
- flock/cli/config.py +0 -8
- flock/cli/constants.py +0 -36
- flock/cli/create_agent.py +0 -1
- flock/cli/create_flock.py +0 -280
- flock/cli/execute_flock.py +0 -620
- flock/cli/load_agent.py +0 -1
- flock/cli/load_examples.py +0 -1
- flock/cli/load_flock.py +0 -192
- flock/cli/load_release_notes.py +0 -20
- flock/cli/loaded_flock_cli.py +0 -254
- flock/cli/manage_agents.py +0 -459
- flock/cli/registry_management.py +0 -889
- flock/cli/runner.py +0 -41
- flock/cli/settings.py +0 -857
- flock/cli/utils.py +0 -135
- flock/cli/view_results.py +0 -29
- flock/cli/yaml_editor.py +0 -396
- flock/components/__init__.py +0 -30
- flock/components/evaluation/__init__.py +0 -9
- flock/components/evaluation/declarative_evaluation_component.py +0 -606
- flock/components/routing/__init__.py +0 -15
- flock/components/routing/conditional_routing_component.py +0 -494
- flock/components/routing/default_routing_component.py +0 -103
- flock/components/routing/llm_routing_component.py +0 -206
- flock/components/utility/__init__.py +0 -22
- flock/components/utility/example_utility_component.py +0 -250
- flock/components/utility/feedback_utility_component.py +0 -206
- flock/components/utility/memory_utility_component.py +0 -550
- flock/components/utility/metrics_utility_component.py +0 -700
- flock/config.py +0 -61
- flock/core/__init__.py +0 -110
- flock/core/agent/__init__.py +0 -16
- flock/core/agent/default_agent.py +0 -216
- flock/core/agent/flock_agent_components.py +0 -104
- flock/core/agent/flock_agent_execution.py +0 -101
- flock/core/agent/flock_agent_integration.py +0 -260
- flock/core/agent/flock_agent_lifecycle.py +0 -186
- flock/core/agent/flock_agent_serialization.py +0 -381
- flock/core/api/__init__.py +0 -10
- flock/core/api/custom_endpoint.py +0 -45
- flock/core/api/endpoints.py +0 -254
- flock/core/api/main.py +0 -162
- flock/core/api/models.py +0 -97
- flock/core/api/run_store.py +0 -224
- flock/core/api/runner.py +0 -44
- flock/core/api/service.py +0 -214
- flock/core/component/__init__.py +0 -15
- flock/core/component/agent_component_base.py +0 -309
- flock/core/component/evaluation_component.py +0 -62
- flock/core/component/routing_component.py +0 -74
- flock/core/component/utility_component.py +0 -69
- flock/core/config/flock_agent_config.py +0 -58
- flock/core/config/scheduled_agent_config.py +0 -40
- flock/core/context/context.py +0 -213
- flock/core/context/context_manager.py +0 -37
- flock/core/context/context_vars.py +0 -10
- flock/core/evaluation/utils.py +0 -396
- flock/core/execution/batch_executor.py +0 -369
- flock/core/execution/evaluation_executor.py +0 -438
- flock/core/execution/local_executor.py +0 -31
- flock/core/execution/opik_executor.py +0 -103
- flock/core/execution/temporal_executor.py +0 -164
- flock/core/flock.py +0 -634
- flock/core/flock_agent.py +0 -336
- flock/core/flock_factory.py +0 -613
- flock/core/flock_scheduler.py +0 -166
- flock/core/flock_server_manager.py +0 -136
- flock/core/interpreter/python_interpreter.py +0 -689
- flock/core/mcp/__init__.py +0 -1
- flock/core/mcp/flock_mcp_server.py +0 -680
- flock/core/mcp/mcp_client_manager.py +0 -201
- flock/core/mcp/types/__init__.py +0 -1
- flock/core/mixin/dspy_integration.py +0 -403
- flock/core/mixin/prompt_parser.py +0 -125
- flock/core/orchestration/__init__.py +0 -15
- flock/core/orchestration/flock_batch_processor.py +0 -94
- flock/core/orchestration/flock_evaluator.py +0 -113
- flock/core/orchestration/flock_execution.py +0 -295
- flock/core/orchestration/flock_initialization.py +0 -149
- flock/core/orchestration/flock_server_manager.py +0 -67
- flock/core/orchestration/flock_web_server.py +0 -117
- flock/core/registry/__init__.py +0 -45
- flock/core/registry/agent_registry.py +0 -69
- flock/core/registry/callable_registry.py +0 -139
- flock/core/registry/component_discovery.py +0 -142
- flock/core/registry/component_registry.py +0 -64
- flock/core/registry/config_mapping.py +0 -64
- flock/core/registry/decorators.py +0 -137
- flock/core/registry/registry_hub.py +0 -205
- flock/core/registry/server_registry.py +0 -57
- flock/core/registry/type_registry.py +0 -86
- flock/core/serialization/__init__.py +0 -13
- flock/core/serialization/callable_registry.py +0 -52
- flock/core/serialization/flock_serializer.py +0 -832
- flock/core/serialization/json_encoder.py +0 -41
- flock/core/serialization/secure_serializer.py +0 -175
- flock/core/serialization/serializable.py +0 -342
- flock/core/serialization/serialization_utils.py +0 -412
- flock/core/util/file_path_utils.py +0 -223
- flock/core/util/hydrator.py +0 -309
- flock/core/util/input_resolver.py +0 -164
- flock/core/util/loader.py +0 -59
- flock/core/util/splitter.py +0 -219
- flock/di.py +0 -27
- flock/platform/docker_tools.py +0 -49
- flock/platform/jaeger_install.py +0 -86
- flock/webapp/__init__.py +0 -1
- flock/webapp/app/__init__.py +0 -0
- flock/webapp/app/api/__init__.py +0 -0
- flock/webapp/app/api/agent_management.py +0 -241
- flock/webapp/app/api/execution.py +0 -709
- flock/webapp/app/api/flock_management.py +0 -129
- flock/webapp/app/api/registry_viewer.py +0 -30
- flock/webapp/app/chat.py +0 -665
- flock/webapp/app/config.py +0 -104
- flock/webapp/app/dependencies.py +0 -117
- flock/webapp/app/main.py +0 -1070
- flock/webapp/app/middleware.py +0 -113
- flock/webapp/app/models_ui.py +0 -7
- flock/webapp/app/services/__init__.py +0 -0
- flock/webapp/app/services/feedback_file_service.py +0 -363
- flock/webapp/app/services/flock_service.py +0 -337
- flock/webapp/app/services/sharing_models.py +0 -81
- flock/webapp/app/services/sharing_store.py +0 -762
- flock/webapp/app/templates/theme_mapper.html +0 -326
- flock/webapp/app/theme_mapper.py +0 -812
- flock/webapp/app/utils.py +0 -85
- flock/webapp/run.py +0 -215
- flock/webapp/static/css/chat.css +0 -301
- flock/webapp/static/css/components.css +0 -167
- flock/webapp/static/css/header.css +0 -39
- flock/webapp/static/css/layout.css +0 -46
- flock/webapp/static/css/sidebar.css +0 -127
- flock/webapp/static/css/two-pane.css +0 -48
- flock/webapp/templates/base.html +0 -200
- flock/webapp/templates/chat.html +0 -152
- flock/webapp/templates/chat_settings.html +0 -19
- flock/webapp/templates/flock_editor.html +0 -16
- flock/webapp/templates/index.html +0 -12
- flock/webapp/templates/partials/_agent_detail_form.html +0 -93
- flock/webapp/templates/partials/_agent_list.html +0 -18
- flock/webapp/templates/partials/_agent_manager_view.html +0 -51
- flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
- flock/webapp/templates/partials/_chat_container.html +0 -15
- flock/webapp/templates/partials/_chat_messages.html +0 -57
- flock/webapp/templates/partials/_chat_settings_form.html +0 -85
- flock/webapp/templates/partials/_create_flock_form.html +0 -50
- flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
- flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
- flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
- flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
- flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
- flock/webapp/templates/partials/_env_vars_table.html +0 -23
- flock/webapp/templates/partials/_execution_form.html +0 -118
- flock/webapp/templates/partials/_execution_view_container.html +0 -28
- flock/webapp/templates/partials/_flock_file_list.html +0 -23
- flock/webapp/templates/partials/_flock_properties_form.html +0 -52
- flock/webapp/templates/partials/_flock_upload_form.html +0 -16
- flock/webapp/templates/partials/_header_flock_status.html +0 -5
- flock/webapp/templates/partials/_load_manager_view.html +0 -49
- flock/webapp/templates/partials/_registry_table.html +0 -25
- flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
- flock/webapp/templates/partials/_results_display.html +0 -78
- flock/webapp/templates/partials/_settings_env_content.html +0 -9
- flock/webapp/templates/partials/_settings_theme_content.html +0 -14
- flock/webapp/templates/partials/_settings_view.html +0 -36
- flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
- flock/webapp/templates/partials/_share_link_snippet.html +0 -35
- flock/webapp/templates/partials/_sidebar.html +0 -74
- flock/webapp/templates/partials/_streaming_results_container.html +0 -195
- flock/webapp/templates/partials/_structured_data_view.html +0 -40
- flock/webapp/templates/partials/_theme_preview.html +0 -36
- flock/webapp/templates/registry_viewer.html +0 -84
- flock/webapp/templates/shared_run_page.html +0 -140
- flock/workflow/__init__.py +0 -0
- flock/workflow/activities.py +0 -196
- flock/workflow/agent_activities.py +0 -24
- flock/workflow/agent_execution_activity.py +0 -202
- flock/workflow/flock_workflow.py +0 -214
- flock/workflow/temporal_config.py +0 -96
- flock/workflow/temporal_setup.py +0 -68
- flock_core-0.5.0b28.dist-info/METADATA +0 -274
- flock_core-0.5.0b28.dist-info/RECORD +0 -561
- flock_core-0.5.0b28.dist-info/entry_points.txt +0 -2
- /flock/{core/logging → logging}/formatters/themes.py +0 -0
- /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
- /flock/{core/mcp → mcp}/util/__init__.py +0 -0
- {flock_core-0.5.0b28.dist-info → flock_core-0.5.56b0.dist-info}/WHEEL +0 -0
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
# src/flock/core/orchestration/flock_initialization.py
|
|
2
|
-
"""Initialization functionality for Flock orchestrator."""
|
|
3
|
-
|
|
4
|
-
import os
|
|
5
|
-
import uuid
|
|
6
|
-
from typing import TYPE_CHECKING
|
|
7
|
-
|
|
8
|
-
from opentelemetry.baggage import get_baggage, set_baggage
|
|
9
|
-
|
|
10
|
-
from flock.core.logging.logging import get_logger
|
|
11
|
-
from flock.core.registry import get_registry
|
|
12
|
-
from flock.core.util.cli_helper import init_console
|
|
13
|
-
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from flock.core.flock import Flock
|
|
16
|
-
from flock.core.flock_agent import FlockAgent
|
|
17
|
-
from flock.core.mcp.flock_mcp_server import FlockMCPServer
|
|
18
|
-
|
|
19
|
-
logger = get_logger("flock.initialization")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class FlockInitialization:
|
|
23
|
-
"""Handles initialization logic for Flock orchestrator."""
|
|
24
|
-
|
|
25
|
-
def __init__(self, flock: "Flock"):
|
|
26
|
-
self.flock = flock
|
|
27
|
-
|
|
28
|
-
def setup(
|
|
29
|
-
self,
|
|
30
|
-
agents: list["FlockAgent"] | None = None,
|
|
31
|
-
servers: list["FlockMCPServer"] | None = None,
|
|
32
|
-
) -> None:
|
|
33
|
-
"""Handle all initialization side effects and setup."""
|
|
34
|
-
# Workaround: newer litellm logging tries to import proxy dependencies (apscheduler)
|
|
35
|
-
# via cold storage logging even for non-proxy usage. Avoid hard dependency by
|
|
36
|
-
# pre-stubbing the `litellm.proxy.proxy_server` module with a minimal object.
|
|
37
|
-
self._patch_litellm_proxy_imports()
|
|
38
|
-
# Register passed servers first (agents may depend on them)
|
|
39
|
-
if servers:
|
|
40
|
-
self._register_servers(servers)
|
|
41
|
-
|
|
42
|
-
# Register passed agents
|
|
43
|
-
if agents:
|
|
44
|
-
self._register_agents(agents)
|
|
45
|
-
|
|
46
|
-
# Initialize console if needed for banner
|
|
47
|
-
if self.flock.show_flock_banner:
|
|
48
|
-
init_console(clear_screen=True, show_banner=self.flock.show_flock_banner, model=self.flock.model)
|
|
49
|
-
|
|
50
|
-
# Set Temporal debug environment variable
|
|
51
|
-
self._set_temporal_debug_flag()
|
|
52
|
-
|
|
53
|
-
# Ensure session ID exists in baggage
|
|
54
|
-
self._ensure_session_id()
|
|
55
|
-
|
|
56
|
-
# Auto-discover components
|
|
57
|
-
registry = get_registry()
|
|
58
|
-
registry.discover_and_register_components()
|
|
59
|
-
|
|
60
|
-
# Setup Opik if enabled
|
|
61
|
-
if self.flock.enable_opik:
|
|
62
|
-
self._setup_opik()
|
|
63
|
-
|
|
64
|
-
logger.info(
|
|
65
|
-
"Flock instance initialized",
|
|
66
|
-
name=self.flock.name,
|
|
67
|
-
model=self.flock.model,
|
|
68
|
-
enable_temporal=self.flock.enable_temporal,
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
def _patch_litellm_proxy_imports(self) -> None:
|
|
72
|
-
"""Stub litellm proxy_server to avoid optional proxy deps when not used.
|
|
73
|
-
|
|
74
|
-
Some litellm versions import `litellm.proxy.proxy_server` during standard logging
|
|
75
|
-
to read `general_settings`, which pulls in optional dependencies like `apscheduler`.
|
|
76
|
-
We provide a stub so imports succeed but cold storage remains disabled.
|
|
77
|
-
"""
|
|
78
|
-
try:
|
|
79
|
-
import sys
|
|
80
|
-
import types
|
|
81
|
-
|
|
82
|
-
if "litellm.proxy.proxy_server" not in sys.modules:
|
|
83
|
-
stub = types.ModuleType("litellm.proxy.proxy_server")
|
|
84
|
-
# Minimal surface that cold_storage_handler accesses
|
|
85
|
-
setattr(stub, "general_settings", {})
|
|
86
|
-
sys.modules["litellm.proxy.proxy_server"] = stub
|
|
87
|
-
except Exception as e:
|
|
88
|
-
# Safe to ignore; worst case litellm will log a warning
|
|
89
|
-
logger.debug(f"Failed to stub litellm proxy_server: {e}")
|
|
90
|
-
|
|
91
|
-
def _register_servers(self, servers: list["FlockMCPServer"]) -> None:
|
|
92
|
-
"""Register servers with the Flock instance."""
|
|
93
|
-
from flock.core.mcp.flock_mcp_server import (
|
|
94
|
-
FlockMCPServer as ConcreteFlockMCPServer,
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
for server in servers:
|
|
98
|
-
if isinstance(server, ConcreteFlockMCPServer):
|
|
99
|
-
self.flock.add_server(server)
|
|
100
|
-
else:
|
|
101
|
-
logger.warning(
|
|
102
|
-
f"Item provided in 'servers' list is not a FlockMCPServer: {type(server)}"
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
def _register_agents(self, agents: list["FlockAgent"]) -> None:
|
|
106
|
-
"""Register agents with the Flock instance."""
|
|
107
|
-
from flock.core.flock_agent import FlockAgent as ConcreteFlockAgent
|
|
108
|
-
|
|
109
|
-
for agent in agents:
|
|
110
|
-
if isinstance(agent, ConcreteFlockAgent):
|
|
111
|
-
self.flock.add_agent(agent)
|
|
112
|
-
else:
|
|
113
|
-
logger.warning(
|
|
114
|
-
f"Item provided in 'agents' list is not a FlockAgent: {type(agent)}"
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
def _set_temporal_debug_flag(self) -> None:
|
|
118
|
-
"""Set or remove LOCAL_DEBUG env var based on enable_temporal."""
|
|
119
|
-
if not self.flock.enable_temporal:
|
|
120
|
-
if "LOCAL_DEBUG" not in os.environ:
|
|
121
|
-
os.environ["LOCAL_DEBUG"] = "1"
|
|
122
|
-
logger.debug("Set LOCAL_DEBUG environment variable for local execution.")
|
|
123
|
-
elif "LOCAL_DEBUG" in os.environ:
|
|
124
|
-
del os.environ["LOCAL_DEBUG"]
|
|
125
|
-
logger.debug("Removed LOCAL_DEBUG environment variable for Temporal execution.")
|
|
126
|
-
|
|
127
|
-
def _ensure_session_id(self) -> None:
|
|
128
|
-
"""Ensure a session_id exists in the OpenTelemetry baggage."""
|
|
129
|
-
session_id = get_baggage("session_id")
|
|
130
|
-
if not session_id:
|
|
131
|
-
session_id = str(uuid.uuid4())
|
|
132
|
-
set_baggage("session_id", session_id)
|
|
133
|
-
logger.debug(f"Generated new session_id: {session_id}")
|
|
134
|
-
|
|
135
|
-
def _setup_opik(self) -> None:
|
|
136
|
-
"""Setup Opik integration."""
|
|
137
|
-
try:
|
|
138
|
-
import dspy
|
|
139
|
-
import opik
|
|
140
|
-
from opik.integrations.dspy.callback import OpikCallback
|
|
141
|
-
|
|
142
|
-
opik.configure(use_local=True, automatic_approvals=True)
|
|
143
|
-
opik_callback = OpikCallback(project_name=self.flock.name, log_graph=True)
|
|
144
|
-
dspy.settings.configure(callbacks=[opik_callback])
|
|
145
|
-
logger.info("Opik integration enabled")
|
|
146
|
-
except ImportError as e:
|
|
147
|
-
logger.error(f"Failed to setup Opik integration: {e}")
|
|
148
|
-
logger.warning("Disabling Opik integration")
|
|
149
|
-
self.flock.enable_opik = False
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# src/flock/core/orchestration/flock_server_manager.py
|
|
2
|
-
"""Server management functionality for Flock orchestrator."""
|
|
3
|
-
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
5
|
-
|
|
6
|
-
from flock.core.flock_server_manager import (
|
|
7
|
-
FlockServerManager as InternalServerManager,
|
|
8
|
-
)
|
|
9
|
-
from flock.core.logging.logging import get_logger
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from flock.core.flock import Flock
|
|
13
|
-
from flock.core.mcp.flock_mcp_server import FlockMCPServer
|
|
14
|
-
|
|
15
|
-
logger = get_logger("flock.server_manager")
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class FlockServerManager:
|
|
19
|
-
"""Handles server lifecycle management for Flock orchestrator."""
|
|
20
|
-
|
|
21
|
-
def __init__(self, flock: "Flock"):
|
|
22
|
-
self.flock = flock
|
|
23
|
-
# Use the existing internal server manager
|
|
24
|
-
self._internal_mgr = InternalServerManager()
|
|
25
|
-
|
|
26
|
-
def add_server(self, server: "FlockMCPServer") -> "FlockMCPServer":
|
|
27
|
-
"""Adds a server instance to this Flock configuration and registry as well as set it up to be managed by internal manager."""
|
|
28
|
-
from flock.core.mcp.flock_mcp_server import (
|
|
29
|
-
FlockMCPServer as ConcreteFlockMCPServer,
|
|
30
|
-
)
|
|
31
|
-
from flock.core.registry import get_registry
|
|
32
|
-
|
|
33
|
-
registry = get_registry()
|
|
34
|
-
|
|
35
|
-
if not isinstance(server, ConcreteFlockMCPServer):
|
|
36
|
-
raise TypeError("Provided object is not a FlockMCPServer instance.")
|
|
37
|
-
if not server.config.name:
|
|
38
|
-
raise ValueError("Server must have a name.")
|
|
39
|
-
|
|
40
|
-
if server.config.name in self.flock.servers:
|
|
41
|
-
raise ValueError(
|
|
42
|
-
f"Server with this name already exists. Name: '{server.config.name}'"
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
self.flock._servers[server.config.name] = server
|
|
46
|
-
registry.register_server(server) # Register globally.
|
|
47
|
-
|
|
48
|
-
# Prepare server to be managed by the FlockServerManager
|
|
49
|
-
logger.info(f"Adding server '{server.config.name}' to managed list.")
|
|
50
|
-
self._internal_mgr.add_server_sync(server=server)
|
|
51
|
-
logger.info(f"Server '{server.config.name}' is now on managed list.")
|
|
52
|
-
|
|
53
|
-
logger.info(f"Server '{server.config.name}' added to Flock '{self.flock.name}'")
|
|
54
|
-
return server
|
|
55
|
-
|
|
56
|
-
async def __aenter__(self):
|
|
57
|
-
"""Start all managed servers."""
|
|
58
|
-
return await self._internal_mgr.__aenter__()
|
|
59
|
-
|
|
60
|
-
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
61
|
-
"""Cleanup all managed servers."""
|
|
62
|
-
return await self._internal_mgr.__aexit__(exc_type, exc_val, exc_tb)
|
|
63
|
-
|
|
64
|
-
@property
|
|
65
|
-
def servers(self) -> dict[str, "FlockMCPServer"]:
|
|
66
|
-
"""Returns the dictionary of servers managed by this Flock instance."""
|
|
67
|
-
return self.flock._servers
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
# src/flock/core/orchestration/flock_web_server.py
|
|
2
|
-
"""Web server and CLI management functionality for Flock orchestrator."""
|
|
3
|
-
|
|
4
|
-
from collections.abc import Callable, Sequence
|
|
5
|
-
from typing import TYPE_CHECKING, Any
|
|
6
|
-
|
|
7
|
-
from flock.core.logging.logging import get_logger
|
|
8
|
-
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from flock.core.api.custom_endpoint import FlockEndpoint
|
|
11
|
-
from flock.core.flock import Flock
|
|
12
|
-
from flock.core.flock_agent import FlockAgent
|
|
13
|
-
|
|
14
|
-
logger = get_logger("flock.web_server")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class FlockWebServer:
|
|
18
|
-
"""Handles web server and CLI functionality for Flock orchestrator."""
|
|
19
|
-
|
|
20
|
-
def __init__(self, flock: "Flock"):
|
|
21
|
-
self.flock = flock
|
|
22
|
-
|
|
23
|
-
def serve(
|
|
24
|
-
self,
|
|
25
|
-
host: str = "127.0.0.1",
|
|
26
|
-
port: int = 8344,
|
|
27
|
-
server_name: str = "Flock Server",
|
|
28
|
-
ui: bool = True,
|
|
29
|
-
chat: bool = False,
|
|
30
|
-
chat_agent: str | None = None,
|
|
31
|
-
chat_message_key: str = "message",
|
|
32
|
-
chat_history_key: str = "history",
|
|
33
|
-
chat_response_key: str = "response",
|
|
34
|
-
ui_theme: str | None = None,
|
|
35
|
-
custom_endpoints: Sequence["FlockEndpoint"]
|
|
36
|
-
| dict[tuple[str, list[str] | None], Callable[..., Any]]
|
|
37
|
-
| None = None,
|
|
38
|
-
) -> None:
|
|
39
|
-
"""Launch an HTTP server that exposes the core REST API and, optionally, the browser-based UI."""
|
|
40
|
-
try:
|
|
41
|
-
from flock.webapp.run import start_unified_server
|
|
42
|
-
except ImportError:
|
|
43
|
-
logger.error(
|
|
44
|
-
"Web application components not found (flock.webapp.run). "
|
|
45
|
-
"Cannot start HTTP server. Ensure webapp dependencies are installed."
|
|
46
|
-
)
|
|
47
|
-
return
|
|
48
|
-
|
|
49
|
-
logger.info(
|
|
50
|
-
f"Attempting to start server for Flock '{self.flock.name}' on {host}:{port}. UI enabled: {ui}"
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
start_unified_server(
|
|
54
|
-
flock_instance=self.flock,
|
|
55
|
-
host=host,
|
|
56
|
-
port=port,
|
|
57
|
-
server_title=server_name,
|
|
58
|
-
enable_ui_routes=ui,
|
|
59
|
-
enable_chat_routes=chat,
|
|
60
|
-
ui_theme=ui_theme,
|
|
61
|
-
custom_endpoints=custom_endpoints,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
def start_api(
|
|
65
|
-
self,
|
|
66
|
-
host: str = "127.0.0.1",
|
|
67
|
-
port: int = 8344,
|
|
68
|
-
server_name: str = "Flock Server",
|
|
69
|
-
create_ui: bool = True,
|
|
70
|
-
ui_theme: str | None = None,
|
|
71
|
-
custom_endpoints: Sequence["FlockEndpoint"]
|
|
72
|
-
| dict[tuple[str, list[str] | None], Callable[..., Any]]
|
|
73
|
-
| None = None,
|
|
74
|
-
) -> None:
|
|
75
|
-
"""Deprecated: Use serve() instead."""
|
|
76
|
-
import warnings
|
|
77
|
-
|
|
78
|
-
warnings.warn(
|
|
79
|
-
"start_api() is deprecated and will be removed in a future release. "
|
|
80
|
-
"Use serve() instead.",
|
|
81
|
-
DeprecationWarning,
|
|
82
|
-
stacklevel=2,
|
|
83
|
-
)
|
|
84
|
-
# Delegate to the new serve() method (create_ui maps to ui)
|
|
85
|
-
return self.serve(
|
|
86
|
-
host=host,
|
|
87
|
-
port=port,
|
|
88
|
-
server_name=server_name,
|
|
89
|
-
ui=create_ui,
|
|
90
|
-
ui_theme=ui_theme,
|
|
91
|
-
custom_endpoints=custom_endpoints,
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
def start_cli(
|
|
95
|
-
self,
|
|
96
|
-
start_agent: "FlockAgent | str | None" = None,
|
|
97
|
-
server_name: str = "Flock CLI",
|
|
98
|
-
show_results: bool = False,
|
|
99
|
-
edit_mode: bool = False,
|
|
100
|
-
) -> None:
|
|
101
|
-
"""Starts an interactive CLI for this Flock instance."""
|
|
102
|
-
try:
|
|
103
|
-
from flock.cli.runner import start_flock_cli
|
|
104
|
-
except ImportError:
|
|
105
|
-
logger.error(
|
|
106
|
-
"CLI components not found. Cannot start CLI. "
|
|
107
|
-
"Ensure CLI dependencies are installed."
|
|
108
|
-
)
|
|
109
|
-
return
|
|
110
|
-
|
|
111
|
-
logger.info(f"Starting CLI for Flock '{self.flock.name}'...")
|
|
112
|
-
start_flock_cli(
|
|
113
|
-
flock=self.flock, # Pass the Flock instance
|
|
114
|
-
server_name=server_name,
|
|
115
|
-
show_results=show_results,
|
|
116
|
-
edit_mode=edit_mode,
|
|
117
|
-
)
|
flock/core/registry/__init__.py
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# src/flock/core/registry/__init__.py
|
|
2
|
-
"""Modern thread-safe registry system using composition pattern.
|
|
3
|
-
|
|
4
|
-
This module provides a complete refactor of the FlockRegistry using
|
|
5
|
-
the proven composition pattern from Flock and FlockAgent refactoring.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
from flock.core.registry.agent_registry import AgentRegistry
|
|
10
|
-
from flock.core.registry.callable_registry import CallableRegistry
|
|
11
|
-
from flock.core.registry.component_discovery import ComponentDiscovery
|
|
12
|
-
|
|
13
|
-
# Specialized registry components (for advanced usage)
|
|
14
|
-
from flock.core.registry.component_registry import ComponentRegistry
|
|
15
|
-
from flock.core.registry.config_mapping import ConfigMapping
|
|
16
|
-
from flock.core.registry.decorators import (
|
|
17
|
-
flock_callable,
|
|
18
|
-
flock_component,
|
|
19
|
-
flock_tool,
|
|
20
|
-
flock_type,
|
|
21
|
-
)
|
|
22
|
-
from flock.core.registry.registry_hub import RegistryHub, get_registry
|
|
23
|
-
from flock.core.registry.server_registry import ServerRegistry
|
|
24
|
-
from flock.core.registry.type_registry import TypeRegistry
|
|
25
|
-
|
|
26
|
-
__all__ = [
|
|
27
|
-
# Main API
|
|
28
|
-
"RegistryHub",
|
|
29
|
-
"get_registry",
|
|
30
|
-
|
|
31
|
-
# Decorators
|
|
32
|
-
"flock_component",
|
|
33
|
-
"flock_tool",
|
|
34
|
-
"flock_callable",
|
|
35
|
-
"flock_type",
|
|
36
|
-
|
|
37
|
-
# Specialized registries (for advanced usage)
|
|
38
|
-
"ComponentRegistry",
|
|
39
|
-
"CallableRegistry",
|
|
40
|
-
"AgentRegistry",
|
|
41
|
-
"ServerRegistry",
|
|
42
|
-
"TypeRegistry",
|
|
43
|
-
"ConfigMapping",
|
|
44
|
-
"ComponentDiscovery",
|
|
45
|
-
]
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# src/flock/core/registry/agent_registry.py
|
|
2
|
-
"""Agent instance registration and lookup functionality."""
|
|
3
|
-
|
|
4
|
-
import threading
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
6
|
-
|
|
7
|
-
from flock.core.logging.logging import get_logger
|
|
8
|
-
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from flock.core.flock_agent import FlockAgent
|
|
11
|
-
|
|
12
|
-
logger = get_logger("registry.agents")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class AgentRegistry:
|
|
16
|
-
"""Manages FlockAgent instance registration and lookup with thread safety."""
|
|
17
|
-
|
|
18
|
-
def __init__(self, lock: threading.RLock):
|
|
19
|
-
self._lock = lock
|
|
20
|
-
self._agents: dict[str, "FlockAgent"] = {}
|
|
21
|
-
|
|
22
|
-
def register_agent(self, agent: "FlockAgent", *, force: bool = False) -> None:
|
|
23
|
-
"""Register a FlockAgent instance by its name.
|
|
24
|
-
|
|
25
|
-
Args:
|
|
26
|
-
agent: The agent instance to register.
|
|
27
|
-
force: If True, allow overwriting an existing **different** agent registered under the same name.
|
|
28
|
-
If False and a conflicting registration exists, a ValueError is raised.
|
|
29
|
-
"""
|
|
30
|
-
if not hasattr(agent, "name") or not agent.name:
|
|
31
|
-
logger.error("Attempted to register an agent without a valid 'name' attribute.")
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
with self._lock:
|
|
35
|
-
if agent.name in self._agents and self._agents[agent.name] is not agent:
|
|
36
|
-
# Same agent already registered → silently ignore; different instance → error/force.
|
|
37
|
-
if not force:
|
|
38
|
-
raise ValueError(
|
|
39
|
-
f"Agent '{agent.name}' already registered with a different instance. "
|
|
40
|
-
"Pass force=True to overwrite the existing registration."
|
|
41
|
-
)
|
|
42
|
-
logger.warning(f"Overwriting existing agent '{agent.name}' registration due to force=True.")
|
|
43
|
-
|
|
44
|
-
self._agents[agent.name] = agent
|
|
45
|
-
logger.debug(f"Registered agent: {agent.name}")
|
|
46
|
-
|
|
47
|
-
def get_agent(self, name: str) -> "FlockAgent | None":
|
|
48
|
-
"""Retrieve a registered FlockAgent instance by name."""
|
|
49
|
-
with self._lock:
|
|
50
|
-
agent = self._agents.get(name)
|
|
51
|
-
if not agent:
|
|
52
|
-
logger.warning(f"Agent '{name}' not found in registry.")
|
|
53
|
-
return agent
|
|
54
|
-
|
|
55
|
-
def get_all_agent_names(self) -> list[str]:
|
|
56
|
-
"""Return a list of names of all registered agents."""
|
|
57
|
-
with self._lock:
|
|
58
|
-
return list(self._agents.keys())
|
|
59
|
-
|
|
60
|
-
def get_all_agents(self) -> dict[str, "FlockAgent"]:
|
|
61
|
-
"""Get all registered agents."""
|
|
62
|
-
with self._lock:
|
|
63
|
-
return self._agents.copy()
|
|
64
|
-
|
|
65
|
-
def clear(self) -> None:
|
|
66
|
-
"""Clear all registered agents."""
|
|
67
|
-
with self._lock:
|
|
68
|
-
self._agents.clear()
|
|
69
|
-
logger.debug("Cleared all registered agents")
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
# src/flock/core/registry/callable_registry.py
|
|
2
|
-
"""Callable function/method registration and lookup functionality."""
|
|
3
|
-
|
|
4
|
-
import builtins
|
|
5
|
-
import importlib
|
|
6
|
-
import threading
|
|
7
|
-
from collections.abc import Callable
|
|
8
|
-
from typing import Any
|
|
9
|
-
|
|
10
|
-
from flock.core.logging.logging import get_logger
|
|
11
|
-
|
|
12
|
-
logger = get_logger("registry.callables")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class CallableRegistry:
|
|
16
|
-
"""Manages callable registration with smart lookup and thread safety."""
|
|
17
|
-
|
|
18
|
-
def __init__(self, lock: threading.RLock):
|
|
19
|
-
self._lock = lock
|
|
20
|
-
self._callables: dict[str, Callable] = {}
|
|
21
|
-
|
|
22
|
-
def register_callable(self, func: Callable, name: str | None = None) -> str | None:
|
|
23
|
-
"""Register a callable (function/method). Returns its path string identifier."""
|
|
24
|
-
path_str = name or self._get_path_string(func)
|
|
25
|
-
if not path_str:
|
|
26
|
-
logger.warning(f"Could not register callable {getattr(func, '__name__', 'unknown')}: Unable to determine path string")
|
|
27
|
-
return None
|
|
28
|
-
|
|
29
|
-
with self._lock:
|
|
30
|
-
if path_str in self._callables and self._callables[path_str] != func:
|
|
31
|
-
logger.warning(f"Callable '{path_str}' already registered with a different function. Overwriting.")
|
|
32
|
-
|
|
33
|
-
self._callables[path_str] = func
|
|
34
|
-
logger.debug(f"Registered callable: '{path_str}' ({getattr(func, '__name__', 'unknown')})")
|
|
35
|
-
return path_str
|
|
36
|
-
|
|
37
|
-
def get_callable(self, name_or_path: str) -> Callable:
|
|
38
|
-
"""Retrieve a callable by its registered name or full path string.
|
|
39
|
-
|
|
40
|
-
Attempts dynamic import if not found directly. Prioritizes exact match,
|
|
41
|
-
then searches for matches ending with '.{name}'.
|
|
42
|
-
"""
|
|
43
|
-
# 1. Try exact match first (covers full paths and simple names if registered that way)
|
|
44
|
-
with self._lock:
|
|
45
|
-
if name_or_path in self._callables:
|
|
46
|
-
logger.debug(f"Found callable '{name_or_path}' directly in registry.")
|
|
47
|
-
return self._callables[name_or_path]
|
|
48
|
-
|
|
49
|
-
# 2. If not found, and it looks like a simple name, search registered paths
|
|
50
|
-
if "." not in name_or_path:
|
|
51
|
-
with self._lock:
|
|
52
|
-
matches = []
|
|
53
|
-
for path_str, func in self._callables.items():
|
|
54
|
-
# Check if path ends with ".{simple_name}" or exactly matches simple_name
|
|
55
|
-
if path_str == name_or_path or path_str.endswith(f".{name_or_path}"):
|
|
56
|
-
matches.append(func)
|
|
57
|
-
|
|
58
|
-
if len(matches) == 1:
|
|
59
|
-
logger.debug(f"Found unique callable for simple name '{name_or_path}' via path '{self.get_callable_path_string(matches[0])}'.")
|
|
60
|
-
return matches[0]
|
|
61
|
-
elif len(matches) > 1:
|
|
62
|
-
# Ambiguous simple name - require full path
|
|
63
|
-
found_paths = [self.get_callable_path_string(f) for f in matches]
|
|
64
|
-
logger.error(f"Ambiguous callable name '{name_or_path}'. Found matches: {found_paths}. Use full path string for lookup.")
|
|
65
|
-
raise KeyError(f"Ambiguous callable name '{name_or_path}'. Use full path string.")
|
|
66
|
-
|
|
67
|
-
# 3. Attempt dynamic import if it looks like a full path
|
|
68
|
-
if "." in name_or_path:
|
|
69
|
-
logger.debug(f"Callable '{name_or_path}' not in registry cache, attempting dynamic import.")
|
|
70
|
-
try:
|
|
71
|
-
module_name, func_name = name_or_path.rsplit(".", 1)
|
|
72
|
-
module = importlib.import_module(module_name)
|
|
73
|
-
func = getattr(module, func_name)
|
|
74
|
-
if callable(func):
|
|
75
|
-
self.register_callable(func, name_or_path) # Cache dynamically imported
|
|
76
|
-
logger.info(f"Successfully imported and registered module callable '{name_or_path}'")
|
|
77
|
-
return func
|
|
78
|
-
else:
|
|
79
|
-
raise TypeError(f"Dynamically imported object '{name_or_path}' is not callable.")
|
|
80
|
-
except (ImportError, AttributeError, TypeError) as e:
|
|
81
|
-
logger.error(f"Failed to dynamically load/find callable '{name_or_path}': {e}", exc_info=False)
|
|
82
|
-
|
|
83
|
-
# 4. Handle built-ins if not found yet (might be redundant if simple name check worked)
|
|
84
|
-
elif name_or_path in builtins.__dict__:
|
|
85
|
-
func = builtins.__dict__[name_or_path]
|
|
86
|
-
if callable(func):
|
|
87
|
-
self.register_callable(func, name_or_path) # Cache it
|
|
88
|
-
logger.info(f"Found and registered built-in callable '{name_or_path}'")
|
|
89
|
-
return func
|
|
90
|
-
|
|
91
|
-
# 5. Final failure
|
|
92
|
-
logger.error(f"Callable '{name_or_path}' not found in registry or via import.")
|
|
93
|
-
raise KeyError(f"Callable '{name_or_path}' not found.")
|
|
94
|
-
|
|
95
|
-
def get_callable_path_string(self, func: Callable) -> str | None:
|
|
96
|
-
"""Get the path string for a callable, registering it if necessary."""
|
|
97
|
-
# First try to find by direct identity
|
|
98
|
-
with self._lock:
|
|
99
|
-
for path_str, registered_func in self._callables.items():
|
|
100
|
-
if func == registered_func:
|
|
101
|
-
logger.debug(f"Found existing path string for callable: '{path_str}'")
|
|
102
|
-
return path_str
|
|
103
|
-
|
|
104
|
-
# If not found by identity, generate path, register, and return
|
|
105
|
-
path_str = self.register_callable(func)
|
|
106
|
-
if path_str:
|
|
107
|
-
logger.debug(f"Generated and registered new path string for callable: '{path_str}'")
|
|
108
|
-
else:
|
|
109
|
-
logger.warning(f"Failed to generate path string for callable {getattr(func, '__name__', 'unknown')}")
|
|
110
|
-
|
|
111
|
-
return path_str
|
|
112
|
-
|
|
113
|
-
def get_all_callables(self) -> dict[str, Callable]:
|
|
114
|
-
"""Get all registered callables."""
|
|
115
|
-
with self._lock:
|
|
116
|
-
return self._callables.copy()
|
|
117
|
-
|
|
118
|
-
def clear(self) -> None:
|
|
119
|
-
"""Clear all registered callables."""
|
|
120
|
-
with self._lock:
|
|
121
|
-
self._callables.clear()
|
|
122
|
-
logger.debug("Cleared all registered callables")
|
|
123
|
-
|
|
124
|
-
@staticmethod
|
|
125
|
-
def _get_path_string(obj: Callable | type) -> str | None:
|
|
126
|
-
"""Generate a unique path string 'module.ClassName' or 'module.function_name'."""
|
|
127
|
-
try:
|
|
128
|
-
module = obj.__module__
|
|
129
|
-
name = obj.__name__
|
|
130
|
-
if module == "builtins":
|
|
131
|
-
return name
|
|
132
|
-
# Check if it's nested (basic check, might not cover all edge cases)
|
|
133
|
-
if "." in name and hasattr(__import__(module).__dict__, name.split(".")[0]):
|
|
134
|
-
# Likely a nested class/method - serialization might need custom handling or pickle
|
|
135
|
-
logger.warning(f"Object {name} appears nested in {module}. Path string might be ambiguous.")
|
|
136
|
-
return f"{module}.{name}"
|
|
137
|
-
except AttributeError:
|
|
138
|
-
logger.warning(f"Could not determine module/name for object: {obj}")
|
|
139
|
-
return None
|