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,260 +0,0 @@
|
|
|
1
|
-
# src/flock/core/agent/flock_agent_integration.py
|
|
2
|
-
"""Tool and server integration functionality for FlockAgent."""
|
|
3
|
-
|
|
4
|
-
from collections.abc import Callable
|
|
5
|
-
from functools import wraps
|
|
6
|
-
from inspect import Parameter, signature
|
|
7
|
-
from typing import TYPE_CHECKING, Any, TypeVar, cast
|
|
8
|
-
|
|
9
|
-
from flock.core.context.context import FlockContext
|
|
10
|
-
from flock.core.logging.logging import get_logger
|
|
11
|
-
from flock.core.mcp.flock_mcp_server import FlockMCPServer
|
|
12
|
-
from pydantic import BaseModel
|
|
13
|
-
from flock.core.registry import get_registry
|
|
14
|
-
from flock.core.serialization.serialization_utils import (
|
|
15
|
-
_format_type_to_string,
|
|
16
|
-
collect_pydantic_models,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
if TYPE_CHECKING:
|
|
20
|
-
from flock.core.flock_agent import FlockAgent
|
|
21
|
-
|
|
22
|
-
logger = get_logger("agent.integration")
|
|
23
|
-
|
|
24
|
-
R = TypeVar("R", bound=str)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def adapt(prop_name: str, fn: Callable[..., R]) -> Callable[[FlockContext], R]:
|
|
28
|
-
"""Coerce *fn* into the canonical ``(ctx: FlockContext) -> str`` form.
|
|
29
|
-
|
|
30
|
-
Acceptable signatures
|
|
31
|
-
---------------------
|
|
32
|
-
1. ``() -> str`` (no parameters)
|
|
33
|
-
2. ``(ctx: FlockContext) -> str`` (exactly one positional parameter)
|
|
34
|
-
|
|
35
|
-
Anything else raises ``TypeError``.
|
|
36
|
-
|
|
37
|
-
The wrapper also enforces at runtime that the result is ``str``.
|
|
38
|
-
"""
|
|
39
|
-
if not callable(fn):
|
|
40
|
-
raise TypeError(f"{prop_name} must be a callable, got {type(fn).__name__}")
|
|
41
|
-
|
|
42
|
-
sig = signature(fn)
|
|
43
|
-
params = list(sig.parameters.values())
|
|
44
|
-
|
|
45
|
-
def _validate_result(res: object) -> R:
|
|
46
|
-
if not isinstance(res, str):
|
|
47
|
-
raise TypeError(
|
|
48
|
-
f"{prop_name} callable must return str, got {type(res).__name__}"
|
|
49
|
-
)
|
|
50
|
-
return cast(R, res)
|
|
51
|
-
|
|
52
|
-
# ── Case 1: () -> str ────────────────────────────────────────────────────
|
|
53
|
-
if len(params) == 0:
|
|
54
|
-
|
|
55
|
-
@wraps(fn)
|
|
56
|
-
def _wrapped(ctx: FlockContext) -> R:
|
|
57
|
-
return _validate_result(fn())
|
|
58
|
-
|
|
59
|
-
return _wrapped
|
|
60
|
-
|
|
61
|
-
# ── Case 2: (ctx) -> str ────────────────────────────────────────────────
|
|
62
|
-
if len(params) == 1:
|
|
63
|
-
p: Parameter = params[0]
|
|
64
|
-
valid_kind = p.kind in (
|
|
65
|
-
Parameter.POSITIONAL_ONLY,
|
|
66
|
-
Parameter.POSITIONAL_OR_KEYWORD,
|
|
67
|
-
)
|
|
68
|
-
valid_annotation = p.annotation in (Parameter.empty, FlockContext)
|
|
69
|
-
has_no_default = p.default is Parameter.empty
|
|
70
|
-
|
|
71
|
-
if valid_kind and valid_annotation and has_no_default:
|
|
72
|
-
|
|
73
|
-
@wraps(fn)
|
|
74
|
-
def _wrapped(ctx: FlockContext) -> R:
|
|
75
|
-
return _validate_result(fn(ctx)) # type: ignore[arg-type]
|
|
76
|
-
|
|
77
|
-
return _wrapped
|
|
78
|
-
|
|
79
|
-
# ── Anything else: reject ───────────────────────────────────────────────
|
|
80
|
-
raise TypeError(
|
|
81
|
-
f"{prop_name} callable must be () -> str or (ctx: FlockContext) -> str; "
|
|
82
|
-
f"got signature {sig}"
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
class FlockAgentIntegration:
|
|
86
|
-
"""Handles tool and server integration for FlockAgent including MCP servers and callable tools."""
|
|
87
|
-
|
|
88
|
-
def __init__(self, agent: "FlockAgent"):
|
|
89
|
-
self.agent = agent
|
|
90
|
-
|
|
91
|
-
def _resolve(self, raw: str | Callable[..., str], name: str, ctx: FlockContext | None) -> str | None:
|
|
92
|
-
# Support Pydantic BaseModel classes (alternative I/O definitions)
|
|
93
|
-
try:
|
|
94
|
-
if isinstance(raw, type) and issubclass(raw, BaseModel):
|
|
95
|
-
return self._build_spec_from_pydantic(raw)
|
|
96
|
-
# Also support instances directly (use their class schema)
|
|
97
|
-
if isinstance(raw, BaseModel):
|
|
98
|
-
return self._build_spec_from_pydantic(type(raw))
|
|
99
|
-
except Exception:
|
|
100
|
-
# If introspection failed, fall through to normal handling
|
|
101
|
-
pass
|
|
102
|
-
|
|
103
|
-
if callable(raw):
|
|
104
|
-
raw = adapt(name, raw)(ctx or FlockContext())
|
|
105
|
-
return raw
|
|
106
|
-
|
|
107
|
-
def _build_spec_from_pydantic(self, model_cls: type[BaseModel]) -> str:
|
|
108
|
-
"""Builds a flock I/O spec string from a Pydantic BaseModel class.
|
|
109
|
-
|
|
110
|
-
Format per field: "name: type | description"; description omitted when empty.
|
|
111
|
-
Also ensures involved Pydantic models are registered in the TypeRegistry
|
|
112
|
-
so type resolution works when constructing DSPy signatures.
|
|
113
|
-
"""
|
|
114
|
-
# Proactively register this model and any nested models
|
|
115
|
-
try:
|
|
116
|
-
registry = get_registry()
|
|
117
|
-
registry.register_type(model_cls, name=model_cls.__name__)
|
|
118
|
-
# Register nested Pydantic models used in type hints
|
|
119
|
-
if hasattr(model_cls, "model_fields"):
|
|
120
|
-
for _, f in model_cls.model_fields.items():
|
|
121
|
-
ann = getattr(f, "annotation", None)
|
|
122
|
-
for m in collect_pydantic_models(ann):
|
|
123
|
-
registry.register_type(m, name=m.__name__)
|
|
124
|
-
except Exception:
|
|
125
|
-
# Registration best-effort; continue building spec
|
|
126
|
-
pass
|
|
127
|
-
|
|
128
|
-
fields = []
|
|
129
|
-
# Pydantic v2: class-level model_fields
|
|
130
|
-
if not hasattr(model_cls, "model_fields") or model_cls.model_fields is None: # type: ignore[attr-defined]
|
|
131
|
-
return ""
|
|
132
|
-
|
|
133
|
-
for name, field in model_cls.model_fields.items(): # type: ignore[attr-defined]
|
|
134
|
-
type_hint = getattr(field, "annotation", None)
|
|
135
|
-
type_str = _format_type_to_string(type_hint) if type_hint is not None else "str"
|
|
136
|
-
desc = getattr(field, "description", None) or ""
|
|
137
|
-
if desc:
|
|
138
|
-
fields.append(f"{name}: {type_str} | {desc}")
|
|
139
|
-
else:
|
|
140
|
-
fields.append(f"{name}: {type_str}")
|
|
141
|
-
|
|
142
|
-
return ", ".join(fields)
|
|
143
|
-
|
|
144
|
-
def resolve_description(self, context: FlockContext | None = None) -> str | None:
|
|
145
|
-
"""Resolve the agent's description, handling callable descriptions."""
|
|
146
|
-
return self._resolve(self.agent.description_spec, "description", context)
|
|
147
|
-
|
|
148
|
-
def resolve_input(self, context: FlockContext | None = None) -> str | None:
|
|
149
|
-
"""Resolve the agent's input, handling callable inputs."""
|
|
150
|
-
return self._resolve(self.agent.input_spec, "input", context)
|
|
151
|
-
|
|
152
|
-
def resolve_output(self, context: FlockContext | None = None) -> str | None:
|
|
153
|
-
"""Resolve the agent's output, handling callable outputs."""
|
|
154
|
-
return self._resolve(self.agent.output_spec, "output", context)
|
|
155
|
-
|
|
156
|
-
def resolve_next_agent(self, context: FlockContext | None = None) -> str | None:
|
|
157
|
-
"""Resolve the next agent, handling callable next agents."""
|
|
158
|
-
return self._resolve(self.agent.next_agent_spec, "next_agent", context)
|
|
159
|
-
|
|
160
|
-
async def get_mcp_tools(self) -> list[Any]:
|
|
161
|
-
"""Get tools from registered MCP servers."""
|
|
162
|
-
mcp_tools = []
|
|
163
|
-
if self.agent.servers:
|
|
164
|
-
from flock.core.registry import get_registry
|
|
165
|
-
|
|
166
|
-
registry = get_registry() # Get the registry
|
|
167
|
-
for server in self.agent.servers:
|
|
168
|
-
registered_server: FlockMCPServer | None = None
|
|
169
|
-
server_tools = []
|
|
170
|
-
if isinstance(server, FlockMCPServer):
|
|
171
|
-
# check if registered
|
|
172
|
-
server_name = server.config.name
|
|
173
|
-
registered_server = registry.get_server(
|
|
174
|
-
server_name
|
|
175
|
-
)
|
|
176
|
-
else:
|
|
177
|
-
# servers must be registered.
|
|
178
|
-
registered_server = registry.get_server(
|
|
179
|
-
name=server
|
|
180
|
-
)
|
|
181
|
-
if registered_server:
|
|
182
|
-
server_tools = await registered_server.get_tools(
|
|
183
|
-
agent_id=self.agent.agent_id,
|
|
184
|
-
run_id=self.agent.context.run_id,
|
|
185
|
-
)
|
|
186
|
-
else:
|
|
187
|
-
logger.warning(
|
|
188
|
-
f"No Server with name '{server.config.name if isinstance(server, FlockMCPServer) else server}' registered! Skipping."
|
|
189
|
-
)
|
|
190
|
-
mcp_tools = mcp_tools + server_tools
|
|
191
|
-
return mcp_tools
|
|
192
|
-
|
|
193
|
-
async def execute_with_middleware(
|
|
194
|
-
self,
|
|
195
|
-
current_inputs: dict[str, Any],
|
|
196
|
-
registered_tools: list[Any],
|
|
197
|
-
mcp_tools: list[Any]
|
|
198
|
-
) -> dict[str, Any]:
|
|
199
|
-
"""Execute evaluator with optional DI middleware pipeline."""
|
|
200
|
-
container = None
|
|
201
|
-
if self.agent.context is not None:
|
|
202
|
-
container = self.agent.context.get_variable("di.container")
|
|
203
|
-
|
|
204
|
-
# If a MiddlewarePipeline is registered in DI, wrap the evaluator
|
|
205
|
-
result: dict[str, Any] | None = None
|
|
206
|
-
|
|
207
|
-
if container is not None:
|
|
208
|
-
try:
|
|
209
|
-
from wd.di.middleware import (
|
|
210
|
-
MiddlewarePipeline,
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
pipeline: MiddlewarePipeline | None = None
|
|
214
|
-
try:
|
|
215
|
-
pipeline = container.get_service(MiddlewarePipeline)
|
|
216
|
-
except Exception:
|
|
217
|
-
pipeline = None
|
|
218
|
-
|
|
219
|
-
if pipeline is not None:
|
|
220
|
-
# Build execution chain where the evaluator is the terminal handler
|
|
221
|
-
|
|
222
|
-
async def _final_handler():
|
|
223
|
-
return await self.agent.evaluator.evaluate_core(
|
|
224
|
-
self.agent, current_inputs, self.agent.context, registered_tools, mcp_tools
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
idx = 0
|
|
228
|
-
|
|
229
|
-
async def _invoke_next():
|
|
230
|
-
nonlocal idx
|
|
231
|
-
|
|
232
|
-
if idx < len(pipeline._middleware):
|
|
233
|
-
mw = pipeline._middleware[idx]
|
|
234
|
-
idx += 1
|
|
235
|
-
return await mw(self.agent.context, _invoke_next) # type: ignore[arg-type]
|
|
236
|
-
return await _final_handler()
|
|
237
|
-
|
|
238
|
-
# Execute pipeline
|
|
239
|
-
result = await _invoke_next()
|
|
240
|
-
else:
|
|
241
|
-
# No pipeline registered, direct evaluation
|
|
242
|
-
result = await self.agent.evaluator.evaluate_core(
|
|
243
|
-
self.agent, current_inputs, self.agent.context, registered_tools, mcp_tools
|
|
244
|
-
)
|
|
245
|
-
except ImportError:
|
|
246
|
-
# wd.di not installed – fall back
|
|
247
|
-
result = await self.agent.evaluator.evaluate_core(
|
|
248
|
-
self.agent, current_inputs, self.agent.context, registered_tools, mcp_tools
|
|
249
|
-
)
|
|
250
|
-
else:
|
|
251
|
-
# No DI container – standard execution
|
|
252
|
-
result = await self.agent.evaluator.evaluate_core(
|
|
253
|
-
self.agent,
|
|
254
|
-
current_inputs,
|
|
255
|
-
self.agent.context,
|
|
256
|
-
registered_tools,
|
|
257
|
-
mcp_tools,
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
return result
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
# src/flock/core/agent/flock_agent_lifecycle.py
|
|
2
|
-
"""Lifecycle management functionality for FlockAgent."""
|
|
3
|
-
|
|
4
|
-
from typing import TYPE_CHECKING, Any
|
|
5
|
-
|
|
6
|
-
from opentelemetry import trace
|
|
7
|
-
|
|
8
|
-
from flock.core.logging.logging import get_logger
|
|
9
|
-
|
|
10
|
-
if TYPE_CHECKING:
|
|
11
|
-
from flock.core.flock_agent import FlockAgent
|
|
12
|
-
|
|
13
|
-
logger = get_logger("agent.lifecycle")
|
|
14
|
-
tracer = trace.get_tracer(__name__)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class FlockAgentLifecycle:
|
|
18
|
-
"""Handles lifecycle management for FlockAgent including initialization, evaluation, and termination."""
|
|
19
|
-
|
|
20
|
-
def __init__(self, agent: "FlockAgent"):
|
|
21
|
-
self.agent = agent
|
|
22
|
-
|
|
23
|
-
async def initialize(self, inputs: dict[str, Any]) -> None:
|
|
24
|
-
"""Initialize agent and run module initializers."""
|
|
25
|
-
logger.debug(f"Initializing agent '{self.agent.name}'")
|
|
26
|
-
with tracer.start_as_current_span("agent.initialize") as span:
|
|
27
|
-
span.set_attribute("agent.name", self.agent.name)
|
|
28
|
-
span.set_attribute("inputs", str(inputs))
|
|
29
|
-
logger.info(
|
|
30
|
-
f"agent.initialize",
|
|
31
|
-
agent=self.agent.name,
|
|
32
|
-
)
|
|
33
|
-
try:
|
|
34
|
-
for component in self.agent.get_enabled_components():
|
|
35
|
-
await component.on_initialize(self.agent, inputs, self.agent.context)
|
|
36
|
-
except Exception as component_error:
|
|
37
|
-
logger.error(
|
|
38
|
-
"Error during initialize",
|
|
39
|
-
agent=self.agent.name,
|
|
40
|
-
error=str(component_error),
|
|
41
|
-
)
|
|
42
|
-
span.record_exception(component_error)
|
|
43
|
-
|
|
44
|
-
async def terminate(
|
|
45
|
-
self, inputs: dict[str, Any], result: dict[str, Any]
|
|
46
|
-
) -> None:
|
|
47
|
-
"""Terminate agent and run module terminators."""
|
|
48
|
-
logger.debug(f"Terminating agent '{self.agent.name}'")
|
|
49
|
-
with tracer.start_as_current_span("agent.terminate") as span:
|
|
50
|
-
span.set_attribute("agent.name", self.agent.name)
|
|
51
|
-
span.set_attribute("inputs", str(inputs))
|
|
52
|
-
span.set_attribute("result", str(result))
|
|
53
|
-
logger.info(
|
|
54
|
-
f"agent.terminate",
|
|
55
|
-
agent=self.agent.name,
|
|
56
|
-
)
|
|
57
|
-
try:
|
|
58
|
-
current_result = result
|
|
59
|
-
for component in self.agent.get_enabled_components():
|
|
60
|
-
tmp_result = await component.on_terminate(
|
|
61
|
-
self.agent, inputs, self.agent.context, current_result
|
|
62
|
-
)
|
|
63
|
-
# If the component returns a result, use it
|
|
64
|
-
if tmp_result:
|
|
65
|
-
current_result = tmp_result
|
|
66
|
-
|
|
67
|
-
if self.agent.config.write_to_file:
|
|
68
|
-
self.agent._serialization._save_output(self.agent.name, current_result)
|
|
69
|
-
|
|
70
|
-
if self.agent.config.wait_for_input:
|
|
71
|
-
# simple input prompt
|
|
72
|
-
input("Press Enter to continue...")
|
|
73
|
-
|
|
74
|
-
except Exception as component_error:
|
|
75
|
-
logger.error(
|
|
76
|
-
"Error during terminate",
|
|
77
|
-
agent=self.agent.name,
|
|
78
|
-
error=str(component_error),
|
|
79
|
-
)
|
|
80
|
-
span.record_exception(component_error)
|
|
81
|
-
|
|
82
|
-
async def on_error(self, error: Exception, inputs: dict[str, Any]) -> None:
|
|
83
|
-
"""Handle errors and run component error handlers."""
|
|
84
|
-
logger.error(f"Error occurred in agent '{self.agent.name}': {error}")
|
|
85
|
-
with tracer.start_as_current_span("agent.on_error") as span:
|
|
86
|
-
span.set_attribute("agent.name", self.agent.name)
|
|
87
|
-
span.set_attribute("inputs", str(inputs))
|
|
88
|
-
try:
|
|
89
|
-
for component in self.agent.get_enabled_components():
|
|
90
|
-
await component.on_error(self.agent, inputs, self.agent.context, error)
|
|
91
|
-
except Exception as component_error:
|
|
92
|
-
logger.error(
|
|
93
|
-
"Error during on_error",
|
|
94
|
-
agent=self.agent.name,
|
|
95
|
-
error=str(component_error),
|
|
96
|
-
)
|
|
97
|
-
span.record_exception(component_error)
|
|
98
|
-
|
|
99
|
-
async def evaluate(self, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
100
|
-
"""Core evaluation logic, calling the assigned evaluator and components."""
|
|
101
|
-
if not self.agent.evaluator:
|
|
102
|
-
raise RuntimeError(
|
|
103
|
-
f"Agent '{self.agent.name}' has no evaluator assigned."
|
|
104
|
-
)
|
|
105
|
-
with tracer.start_as_current_span("agent.evaluate") as span:
|
|
106
|
-
span.set_attribute("agent.name", self.agent.name)
|
|
107
|
-
span.set_attribute("inputs", str(inputs))
|
|
108
|
-
logger.info(
|
|
109
|
-
f"agent.evaluate",
|
|
110
|
-
agent=self.agent.name,
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
logger.debug(f"Evaluating agent '{self.agent.name}'")
|
|
114
|
-
current_inputs = inputs
|
|
115
|
-
|
|
116
|
-
# Pre-evaluate hooks
|
|
117
|
-
for component in self.agent.get_enabled_components():
|
|
118
|
-
current_inputs = await component.on_pre_evaluate(
|
|
119
|
-
self.agent, current_inputs, self.agent.context
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
# Actual evaluation
|
|
123
|
-
try:
|
|
124
|
-
# Get tools and MCP tools through integration handler
|
|
125
|
-
registered_tools = []
|
|
126
|
-
if self.agent.tools:
|
|
127
|
-
registered_tools = self.agent.tools
|
|
128
|
-
|
|
129
|
-
# Retrieve available mcp_tools if the evaluator needs them
|
|
130
|
-
mcp_tools = []
|
|
131
|
-
if self.agent.servers:
|
|
132
|
-
mcp_tools = await self.agent._integration.get_mcp_tools()
|
|
133
|
-
|
|
134
|
-
# Filter tools based on the agent's whitelist (if it has been provided)
|
|
135
|
-
if self.agent.tool_whitelist is not None and len(self.agent.tool_whitelist) > 0:
|
|
136
|
-
for tool in mcp_tools:
|
|
137
|
-
if hasattr(tool, "name") and tool.name not in self.agent.tool_whitelist:
|
|
138
|
-
mcp_tools.remove(tool)
|
|
139
|
-
for tool in registered_tools:
|
|
140
|
-
if hasattr(tool, "__name__") and tool.__name__ not in self.agent.tool_whitelist:
|
|
141
|
-
registered_tools.remove(tool)
|
|
142
|
-
|
|
143
|
-
# --------------------------------------------------
|
|
144
|
-
# Use evaluator component's evaluate_core method
|
|
145
|
-
# --------------------------------------------------
|
|
146
|
-
result = await self.agent.evaluator.evaluate_core(
|
|
147
|
-
self.agent, current_inputs, self.agent.context, registered_tools, mcp_tools
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
except Exception as eval_error:
|
|
151
|
-
logger.error(
|
|
152
|
-
"Error during evaluate",
|
|
153
|
-
agent=self.agent.name,
|
|
154
|
-
error=str(eval_error),
|
|
155
|
-
)
|
|
156
|
-
span.record_exception(eval_error)
|
|
157
|
-
await self.on_error(
|
|
158
|
-
eval_error, current_inputs
|
|
159
|
-
) # Call error hook
|
|
160
|
-
raise # Re-raise the exception
|
|
161
|
-
|
|
162
|
-
# Post-evaluate hooks
|
|
163
|
-
current_result = result
|
|
164
|
-
for component in self.agent.get_enabled_components():
|
|
165
|
-
tmp_result = await component.on_post_evaluate(
|
|
166
|
-
self.agent,
|
|
167
|
-
current_inputs,
|
|
168
|
-
self.agent.context,
|
|
169
|
-
current_result,
|
|
170
|
-
)
|
|
171
|
-
# If the component returns a result, use it
|
|
172
|
-
if tmp_result:
|
|
173
|
-
current_result = tmp_result
|
|
174
|
-
|
|
175
|
-
# Handle routing logic
|
|
176
|
-
router = self.agent.router
|
|
177
|
-
if router:
|
|
178
|
-
try:
|
|
179
|
-
self.agent.next_agent = await router.determine_next_step(
|
|
180
|
-
self.agent, current_result, self.agent.context
|
|
181
|
-
)
|
|
182
|
-
except Exception as e:
|
|
183
|
-
logger.error(f"Error in routing: {e}")
|
|
184
|
-
|
|
185
|
-
logger.debug(f"Evaluation completed for agent '{self.agent.name}'")
|
|
186
|
-
return current_result
|