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
flock/api/themes.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Theme API Endpoints
|
|
3
|
+
|
|
4
|
+
Serves 300+ terminal color themes from TOML files.
|
|
5
|
+
Themes are loaded from src/flock/themes/
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import toml
|
|
12
|
+
from fastapi import APIRouter, HTTPException
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
router = APIRouter()
|
|
16
|
+
|
|
17
|
+
# Path to themes directory
|
|
18
|
+
THEMES_DIR = Path(__file__).parent.parent / "themes"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@router.get("/themes")
|
|
22
|
+
async def list_themes() -> dict[str, list[str]]:
|
|
23
|
+
"""
|
|
24
|
+
List all available theme names.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Dictionary with 'themes' key containing sorted list of theme names
|
|
28
|
+
"""
|
|
29
|
+
try:
|
|
30
|
+
if not THEMES_DIR.exists():
|
|
31
|
+
return {"themes": []}
|
|
32
|
+
|
|
33
|
+
theme_files = list(THEMES_DIR.glob("*.toml"))
|
|
34
|
+
theme_names = sorted([f.stem for f in theme_files])
|
|
35
|
+
|
|
36
|
+
return {"themes": theme_names}
|
|
37
|
+
except Exception as e:
|
|
38
|
+
raise HTTPException(status_code=500, detail=f"Failed to list themes: {e!s}")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@router.get("/themes/{theme_name}")
|
|
42
|
+
async def get_theme(theme_name: str) -> dict[str, Any]:
|
|
43
|
+
"""
|
|
44
|
+
Get theme data by name.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
theme_name: Name of the theme (without .toml extension)
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Dictionary with 'name' and 'data' containing theme colors
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
HTTPException: If theme not found or failed to load
|
|
54
|
+
"""
|
|
55
|
+
try:
|
|
56
|
+
# Sanitize theme name to prevent path traversal
|
|
57
|
+
theme_name = theme_name.replace("/", "").replace("\\", "").replace("..", "")
|
|
58
|
+
|
|
59
|
+
theme_path = THEMES_DIR / f"{theme_name}.toml"
|
|
60
|
+
|
|
61
|
+
if not theme_path.exists():
|
|
62
|
+
raise HTTPException(status_code=404, detail=f"Theme '{theme_name}' not found")
|
|
63
|
+
|
|
64
|
+
# Load TOML theme
|
|
65
|
+
theme_data = toml.load(theme_path)
|
|
66
|
+
|
|
67
|
+
return {"name": theme_name, "data": theme_data}
|
|
68
|
+
except HTTPException:
|
|
69
|
+
raise
|
|
70
|
+
except Exception as e:
|
|
71
|
+
raise HTTPException(status_code=500, detail=f"Failed to load theme '{theme_name}': {e!s}")
|
flock/artifacts.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Artifact modelling utilities."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from typing import Any
|
|
7
|
+
from uuid import UUID, uuid4
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from flock.registry import type_registry
|
|
12
|
+
from flock.visibility import Visibility, ensure_visibility
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Artifact(BaseModel):
|
|
16
|
+
"""Typed artifact stored on the blackboard."""
|
|
17
|
+
|
|
18
|
+
id: UUID = Field(default_factory=uuid4)
|
|
19
|
+
type: str
|
|
20
|
+
payload: dict[str, Any]
|
|
21
|
+
produced_by: str
|
|
22
|
+
correlation_id: UUID | None = None
|
|
23
|
+
partition_key: str | None = None
|
|
24
|
+
tags: set[str] = Field(default_factory=set)
|
|
25
|
+
visibility: Visibility = Field(default_factory=lambda: ensure_visibility(None))
|
|
26
|
+
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
|
27
|
+
version: int = 1
|
|
28
|
+
|
|
29
|
+
def model_dump_payload(self) -> dict[str, Any]: # pragma: no cover - convenience
|
|
30
|
+
return dict(self.payload)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ArtifactSpec(BaseModel):
|
|
34
|
+
"""Wiring description used for validation on publish."""
|
|
35
|
+
|
|
36
|
+
type_name: str
|
|
37
|
+
model: type[BaseModel]
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def from_model(cls, model: type[BaseModel]) -> ArtifactSpec:
|
|
41
|
+
type_name = type_registry.register(model)
|
|
42
|
+
return cls(type_name=type_name, model=model)
|
|
43
|
+
|
|
44
|
+
def build(
|
|
45
|
+
self,
|
|
46
|
+
*,
|
|
47
|
+
produced_by: str,
|
|
48
|
+
data: dict[str, Any],
|
|
49
|
+
visibility: Visibility | None = None,
|
|
50
|
+
correlation_id: UUID | None = None,
|
|
51
|
+
partition_key: str | None = None,
|
|
52
|
+
tags: set[str] | None = None,
|
|
53
|
+
version: int = 1,
|
|
54
|
+
) -> Artifact:
|
|
55
|
+
payload_model = self.model(**data)
|
|
56
|
+
return Artifact(
|
|
57
|
+
type=self.type_name,
|
|
58
|
+
payload=payload_model.model_dump(),
|
|
59
|
+
produced_by=produced_by,
|
|
60
|
+
visibility=ensure_visibility(visibility),
|
|
61
|
+
correlation_id=correlation_id,
|
|
62
|
+
partition_key=partition_key,
|
|
63
|
+
tags=tags or set(),
|
|
64
|
+
version=version,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ArtifactEnvelope(BaseModel):
|
|
69
|
+
"""Envelope passed to components/engines during evaluation."""
|
|
70
|
+
|
|
71
|
+
artifact: Artifact
|
|
72
|
+
state: dict[str, Any] = Field(default_factory=dict)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
__all__ = [
|
|
76
|
+
"Artifact",
|
|
77
|
+
"ArtifactEnvelope",
|
|
78
|
+
"ArtifactSpec",
|
|
79
|
+
]
|
flock/cli.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Typer-based CLI for blackboard agents."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
|
|
11
|
+
# Lazy import: only import examples when CLI commands are invoked
|
|
12
|
+
# This prevents polluting type_registry on every package import
|
|
13
|
+
from flock.service import BlackboardHTTPService
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
app = typer.Typer(help="Blackboard Agents CLI")
|
|
17
|
+
console = Console()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@app.command()
|
|
21
|
+
def demo(
|
|
22
|
+
topic: str = typer.Option("AI agents collaborating", help="Idea topic"),
|
|
23
|
+
genre: str = typer.Option("comedy", help="Idea genre"),
|
|
24
|
+
) -> None:
|
|
25
|
+
"""Run the demo pipeline locally and stream results to the console."""
|
|
26
|
+
|
|
27
|
+
from flock.examples import Idea, create_demo_orchestrator
|
|
28
|
+
|
|
29
|
+
orchestrator, agents = create_demo_orchestrator()
|
|
30
|
+
idea = Idea(topic=topic, genre=genre)
|
|
31
|
+
|
|
32
|
+
async def _run_demo() -> None:
|
|
33
|
+
await orchestrator.arun(agents["movie"], idea)
|
|
34
|
+
await orchestrator.run_until_idle()
|
|
35
|
+
table = Table(title="Published Artifacts")
|
|
36
|
+
table.add_column("Type")
|
|
37
|
+
table.add_column("Payload", overflow="fold")
|
|
38
|
+
for artifact in await orchestrator.store.list():
|
|
39
|
+
table.add_row(artifact.type, repr(artifact.payload))
|
|
40
|
+
console.print(table)
|
|
41
|
+
|
|
42
|
+
asyncio.run(_run_demo())
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@app.command()
|
|
46
|
+
def list_agents() -> None:
|
|
47
|
+
"""List registered agents for the demo orchestrator."""
|
|
48
|
+
|
|
49
|
+
from flock.examples import create_demo_orchestrator
|
|
50
|
+
|
|
51
|
+
orchestrator, _agents = create_demo_orchestrator()
|
|
52
|
+
table = Table(title="Agents")
|
|
53
|
+
table.add_column("Name")
|
|
54
|
+
table.add_column("Description")
|
|
55
|
+
for agent in orchestrator.agents:
|
|
56
|
+
table.add_row(agent.name, agent.description or "")
|
|
57
|
+
console.print(table)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@app.command()
|
|
61
|
+
def serve(host: str = "127.0.0.1", port: int = 8000) -> None:
|
|
62
|
+
"""Run the HTTP control plane bound to the demo orchestrator."""
|
|
63
|
+
|
|
64
|
+
from flock.examples import create_demo_orchestrator
|
|
65
|
+
|
|
66
|
+
orchestrator, _ = create_demo_orchestrator()
|
|
67
|
+
service = BlackboardHTTPService(orchestrator)
|
|
68
|
+
service.run(host=host, port=port)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def main() -> None:
|
|
72
|
+
app()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
__all__ = ["app", "main"]
|
flock/components.py
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Agent component abstractions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field, create_model
|
|
8
|
+
from typing_extensions import Self, TypeVar
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING: # pragma: no cover - type checking only
|
|
12
|
+
from uuid import UUID
|
|
13
|
+
|
|
14
|
+
from flock.agent import Agent
|
|
15
|
+
from flock.artifacts import Artifact
|
|
16
|
+
from flock.runtime import Context, EvalInputs, EvalResult
|
|
17
|
+
|
|
18
|
+
T = TypeVar("T", bound="AgentComponentConfig")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AgentComponentConfig(BaseModel):
|
|
22
|
+
enabled: bool = True
|
|
23
|
+
model: str | None = None
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def with_fields(cls, **field_definitions) -> type[Self]:
|
|
27
|
+
"""Create a new config class with additional fields.
|
|
28
|
+
|
|
29
|
+
This allows dynamic config creation for components with custom configuration needs.
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
CustomConfig = AgentComponentConfig.with_fields(
|
|
33
|
+
temperature=Field(default=0.7, description="LLM temperature"),
|
|
34
|
+
max_tokens=Field(default=1000, description="Max tokens to generate")
|
|
35
|
+
)
|
|
36
|
+
"""
|
|
37
|
+
return create_model(f"Dynamic{cls.__name__}", __base__=cls, **field_definitions)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AgentComponent(BaseModel):
|
|
41
|
+
name: str | None = None
|
|
42
|
+
config: AgentComponentConfig = Field(default_factory=AgentComponentConfig)
|
|
43
|
+
|
|
44
|
+
async def on_initialize(
|
|
45
|
+
self, agent: Agent, ctx: Context
|
|
46
|
+
) -> None: # pragma: no cover - default no-op
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
async def on_pre_consume(
|
|
50
|
+
self, agent: Agent, ctx: Context, inputs: list[Artifact]
|
|
51
|
+
) -> list[Artifact]:
|
|
52
|
+
return inputs
|
|
53
|
+
|
|
54
|
+
async def on_pre_evaluate(self, agent: Agent, ctx: Context, inputs: EvalInputs) -> EvalInputs:
|
|
55
|
+
return inputs
|
|
56
|
+
|
|
57
|
+
async def on_post_evaluate(
|
|
58
|
+
self, agent: Agent, ctx: Context, inputs: EvalInputs, result: EvalResult
|
|
59
|
+
) -> EvalResult:
|
|
60
|
+
return result
|
|
61
|
+
|
|
62
|
+
async def on_post_publish(
|
|
63
|
+
self, agent: Agent, ctx: Context, artifact: Artifact
|
|
64
|
+
) -> None: # pragma: no cover - default
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
async def on_error(
|
|
68
|
+
self, agent: Agent, ctx: Context, error: Exception
|
|
69
|
+
) -> None: # pragma: no cover - default
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
async def on_terminate(self, agent: Agent, ctx: Context) -> None: # pragma: no cover - default
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class EngineComponent(AgentComponent):
|
|
77
|
+
"""Base class for engine components with built-in conversation context support."""
|
|
78
|
+
|
|
79
|
+
# Configuration for context fetching
|
|
80
|
+
enable_context: bool = Field(
|
|
81
|
+
default=True,
|
|
82
|
+
description="Whether to automatically fetch conversation context based on correlation_id",
|
|
83
|
+
)
|
|
84
|
+
context_max_artifacts: int | None = Field(
|
|
85
|
+
default=None,
|
|
86
|
+
description="Maximum number of artifacts to include in context (None = unlimited)",
|
|
87
|
+
)
|
|
88
|
+
context_exclude_types: set[str] = Field(
|
|
89
|
+
default_factory=set, description="Artifact types to exclude from context"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
async def evaluate(self, agent: Agent, ctx: Context, inputs: EvalInputs) -> EvalResult:
|
|
93
|
+
"""Override this method in your engine implementation."""
|
|
94
|
+
raise NotImplementedError
|
|
95
|
+
|
|
96
|
+
async def fetch_conversation_context(
|
|
97
|
+
self,
|
|
98
|
+
ctx: Context,
|
|
99
|
+
correlation_id: UUID | None = None,
|
|
100
|
+
max_artifacts: int | None = None,
|
|
101
|
+
) -> list[dict[str, Any]]:
|
|
102
|
+
"""Fetch all artifacts with the same correlation_id for conversation context."""
|
|
103
|
+
if not self.enable_context or not ctx:
|
|
104
|
+
return []
|
|
105
|
+
|
|
106
|
+
target_correlation_id = correlation_id or getattr(ctx, "correlation_id", None)
|
|
107
|
+
if not target_correlation_id:
|
|
108
|
+
return []
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
all_artifacts = await ctx.board.list()
|
|
112
|
+
|
|
113
|
+
context_artifacts = [
|
|
114
|
+
a
|
|
115
|
+
for a in all_artifacts
|
|
116
|
+
if (
|
|
117
|
+
a.correlation_id == target_correlation_id
|
|
118
|
+
and a.type not in self.context_exclude_types
|
|
119
|
+
)
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
context_artifacts.sort(key=lambda a: a.created_at)
|
|
123
|
+
|
|
124
|
+
max_limit = max_artifacts if max_artifacts is not None else self.context_max_artifacts
|
|
125
|
+
if max_limit is not None and max_limit > 0:
|
|
126
|
+
context_artifacts = context_artifacts[-max_limit:]
|
|
127
|
+
|
|
128
|
+
context = []
|
|
129
|
+
i = 0
|
|
130
|
+
for artifact in context_artifacts:
|
|
131
|
+
context.append(
|
|
132
|
+
{
|
|
133
|
+
"type": artifact.type,
|
|
134
|
+
"payload": artifact.payload,
|
|
135
|
+
"produced_by": artifact.produced_by,
|
|
136
|
+
"event_number": i,
|
|
137
|
+
# "created_at": artifact.created_at.isoformat(),
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
i += 1
|
|
141
|
+
|
|
142
|
+
return context
|
|
143
|
+
|
|
144
|
+
except Exception:
|
|
145
|
+
return []
|
|
146
|
+
|
|
147
|
+
async def get_latest_artifact_of_type(
|
|
148
|
+
self,
|
|
149
|
+
ctx: Context,
|
|
150
|
+
artifact_type: str,
|
|
151
|
+
correlation_id: UUID | None = None,
|
|
152
|
+
) -> dict[str, Any] | None:
|
|
153
|
+
"""Get the most recent artifact of a specific type in the conversation."""
|
|
154
|
+
context = await self.fetch_conversation_context(ctx, correlation_id)
|
|
155
|
+
matching = [a for a in context if a["type"].endswith(artifact_type)]
|
|
156
|
+
return matching[-1] if matching else None
|
|
157
|
+
|
|
158
|
+
def should_use_context(self, inputs: EvalInputs) -> bool:
|
|
159
|
+
"""Determine if context should be included based on the current inputs."""
|
|
160
|
+
if not self.enable_context:
|
|
161
|
+
return False
|
|
162
|
+
|
|
163
|
+
if inputs.artifacts:
|
|
164
|
+
return inputs.artifacts[0].correlation_id is not None
|
|
165
|
+
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
__all__ = [
|
|
170
|
+
"AgentComponent",
|
|
171
|
+
"AgentComponentConfig",
|
|
172
|
+
"EngineComponent",
|
|
173
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Real-time dashboard event collection for flock-flow.
|
|
2
|
+
|
|
3
|
+
Phase 1: Backend event capture system.
|
|
4
|
+
Phase 3: WebSocket infrastructure for real-time communication.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from flock.dashboard.collector import DashboardEventCollector
|
|
8
|
+
from flock.dashboard.events import (
|
|
9
|
+
AgentActivatedEvent,
|
|
10
|
+
AgentCompletedEvent,
|
|
11
|
+
AgentErrorEvent,
|
|
12
|
+
MessagePublishedEvent,
|
|
13
|
+
StreamingOutputEvent,
|
|
14
|
+
)
|
|
15
|
+
from flock.dashboard.service import DashboardHTTPService
|
|
16
|
+
from flock.dashboard.websocket import WebSocketManager
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"AgentActivatedEvent",
|
|
21
|
+
"AgentCompletedEvent",
|
|
22
|
+
"AgentErrorEvent",
|
|
23
|
+
"DashboardEventCollector",
|
|
24
|
+
"DashboardHTTPService",
|
|
25
|
+
"MessagePublishedEvent",
|
|
26
|
+
"StreamingOutputEvent",
|
|
27
|
+
"WebSocketManager",
|
|
28
|
+
]
|