flock-core 0.4.542__py3-none-any.whl → 0.5.0__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 +1079 -0
- flock/api/themes.py +71 -0
- flock/artifacts.py +86 -0
- flock/cli.py +147 -0
- flock/components.py +189 -0
- flock/dashboard/__init__.py +30 -0
- flock/dashboard/collector.py +559 -0
- flock/dashboard/events.py +188 -0
- flock/dashboard/graph_builder.py +563 -0
- flock/dashboard/launcher.py +235 -0
- flock/dashboard/models/graph.py +156 -0
- flock/dashboard/service.py +991 -0
- flock/dashboard/static_v2/assets/index-DFRnI_mt.js +111 -0
- flock/dashboard/static_v2/assets/index-fPLNdmp1.css +1 -0
- flock/dashboard/static_v2/index.html +13 -0
- flock/dashboard/websocket.py +246 -0
- flock/engines/__init__.py +6 -0
- flock/engines/dspy_engine.py +932 -0
- flock/examples.py +131 -0
- flock/frontend/README.md +778 -0
- flock/frontend/docs/DESIGN_SYSTEM.md +1980 -0
- flock/frontend/index.html +12 -0
- flock/frontend/package-lock.json +4337 -0
- flock/frontend/package.json +48 -0
- flock/frontend/src/App.tsx +139 -0
- flock/frontend/src/__tests__/integration/graph-snapshot.test.tsx +647 -0
- flock/frontend/src/__tests__/integration/indexeddb-persistence.test.tsx +699 -0
- flock/frontend/src/components/common/BuildInfo.tsx +39 -0
- flock/frontend/src/components/common/EmptyState.module.css +115 -0
- flock/frontend/src/components/common/EmptyState.tsx +128 -0
- flock/frontend/src/components/common/ErrorBoundary.module.css +169 -0
- flock/frontend/src/components/common/ErrorBoundary.tsx +118 -0
- flock/frontend/src/components/common/KeyboardShortcutsDialog.css +251 -0
- flock/frontend/src/components/common/KeyboardShortcutsDialog.tsx +151 -0
- flock/frontend/src/components/common/LoadingSpinner.module.css +97 -0
- flock/frontend/src/components/common/LoadingSpinner.tsx +29 -0
- flock/frontend/src/components/controls/PublishControl.css +547 -0
- flock/frontend/src/components/controls/PublishControl.test.tsx +543 -0
- flock/frontend/src/components/controls/PublishControl.tsx +432 -0
- flock/frontend/src/components/details/DetailWindowContainer.tsx +58 -0
- flock/frontend/src/components/details/LiveOutputTab.test.tsx +792 -0
- flock/frontend/src/components/details/LiveOutputTab.tsx +220 -0
- flock/frontend/src/components/details/MessageDetailWindow.tsx +439 -0
- flock/frontend/src/components/details/MessageHistoryTab.tsx +374 -0
- flock/frontend/src/components/details/NodeDetailWindow.test.tsx +501 -0
- flock/frontend/src/components/details/NodeDetailWindow.tsx +218 -0
- flock/frontend/src/components/details/RunStatusTab.tsx +348 -0
- flock/frontend/src/components/details/tabs.test.tsx +1015 -0
- flock/frontend/src/components/filters/ArtifactTypeFilter.tsx +21 -0
- flock/frontend/src/components/filters/CorrelationIDFilter.module.css +102 -0
- flock/frontend/src/components/filters/CorrelationIDFilter.test.tsx +197 -0
- flock/frontend/src/components/filters/CorrelationIDFilter.tsx +121 -0
- flock/frontend/src/components/filters/FilterFlyout.module.css +104 -0
- flock/frontend/src/components/filters/FilterFlyout.tsx +80 -0
- flock/frontend/src/components/filters/FilterPills.module.css +220 -0
- flock/frontend/src/components/filters/FilterPills.test.tsx +189 -0
- flock/frontend/src/components/filters/FilterPills.tsx +143 -0
- flock/frontend/src/components/filters/ProducerFilter.tsx +21 -0
- flock/frontend/src/components/filters/SavedFiltersControl.module.css +60 -0
- flock/frontend/src/components/filters/SavedFiltersControl.test.tsx +158 -0
- flock/frontend/src/components/filters/SavedFiltersControl.tsx +159 -0
- flock/frontend/src/components/filters/TagFilter.tsx +21 -0
- flock/frontend/src/components/filters/TimeRangeFilter.module.css +115 -0
- flock/frontend/src/components/filters/TimeRangeFilter.test.tsx +154 -0
- flock/frontend/src/components/filters/TimeRangeFilter.tsx +110 -0
- flock/frontend/src/components/filters/VisibilityFilter.tsx +21 -0
- flock/frontend/src/components/graph/AgentNode.test.tsx +77 -0
- flock/frontend/src/components/graph/AgentNode.tsx +324 -0
- flock/frontend/src/components/graph/GraphCanvas.tsx +613 -0
- flock/frontend/src/components/graph/MessageFlowEdge.tsx +128 -0
- flock/frontend/src/components/graph/MessageNode.test.tsx +64 -0
- flock/frontend/src/components/graph/MessageNode.tsx +129 -0
- flock/frontend/src/components/graph/MiniMap.tsx +47 -0
- flock/frontend/src/components/graph/TransformEdge.tsx +123 -0
- flock/frontend/src/components/layout/DashboardLayout.css +420 -0
- flock/frontend/src/components/layout/DashboardLayout.tsx +287 -0
- flock/frontend/src/components/layout/Header.module.css +88 -0
- flock/frontend/src/components/layout/Header.tsx +52 -0
- flock/frontend/src/components/modules/HistoricalArtifactsModule.module.css +288 -0
- flock/frontend/src/components/modules/HistoricalArtifactsModule.tsx +450 -0
- flock/frontend/src/components/modules/HistoricalArtifactsModuleWrapper.tsx +13 -0
- flock/frontend/src/components/modules/JsonAttributeRenderer.tsx +140 -0
- flock/frontend/src/components/modules/ModuleRegistry.test.ts +333 -0
- flock/frontend/src/components/modules/ModuleRegistry.ts +93 -0
- flock/frontend/src/components/modules/ModuleWindow.tsx +223 -0
- flock/frontend/src/components/modules/TraceModuleJaeger.tsx +1971 -0
- flock/frontend/src/components/modules/TraceModuleJaegerWrapper.tsx +13 -0
- flock/frontend/src/components/modules/registerModules.ts +29 -0
- flock/frontend/src/components/settings/AdvancedSettings.tsx +175 -0
- flock/frontend/src/components/settings/AppearanceSettings.tsx +185 -0
- flock/frontend/src/components/settings/GraphSettings.tsx +110 -0
- flock/frontend/src/components/settings/MultiSelect.tsx +235 -0
- flock/frontend/src/components/settings/SettingsPanel.css +327 -0
- flock/frontend/src/components/settings/SettingsPanel.tsx +131 -0
- flock/frontend/src/components/settings/ThemeSelector.tsx +298 -0
- flock/frontend/src/components/settings/TracingSettings.tsx +404 -0
- flock/frontend/src/hooks/useKeyboardShortcuts.ts +148 -0
- flock/frontend/src/hooks/useModulePersistence.test.ts +442 -0
- flock/frontend/src/hooks/useModulePersistence.ts +154 -0
- flock/frontend/src/hooks/useModules.ts +157 -0
- flock/frontend/src/hooks/usePersistence.ts +141 -0
- flock/frontend/src/main.tsx +13 -0
- flock/frontend/src/services/api.ts +337 -0
- flock/frontend/src/services/graphService.test.ts +330 -0
- flock/frontend/src/services/graphService.ts +75 -0
- flock/frontend/src/services/indexeddb.test.ts +793 -0
- flock/frontend/src/services/indexeddb.ts +848 -0
- flock/frontend/src/services/layout.test.ts +437 -0
- flock/frontend/src/services/layout.ts +357 -0
- flock/frontend/src/services/themeApplicator.ts +140 -0
- flock/frontend/src/services/themeService.ts +77 -0
- flock/frontend/src/services/websocket.ts +650 -0
- flock/frontend/src/store/filterStore.test.ts +250 -0
- flock/frontend/src/store/filterStore.ts +272 -0
- flock/frontend/src/store/graphStore.test.ts +570 -0
- flock/frontend/src/store/graphStore.ts +462 -0
- flock/frontend/src/store/moduleStore.test.ts +253 -0
- flock/frontend/src/store/moduleStore.ts +75 -0
- flock/frontend/src/store/settingsStore.ts +188 -0
- flock/frontend/src/store/streamStore.ts +68 -0
- flock/frontend/src/store/uiStore.test.ts +54 -0
- flock/frontend/src/store/uiStore.ts +122 -0
- flock/frontend/src/store/wsStore.ts +34 -0
- flock/frontend/src/styles/index.css +15 -0
- flock/frontend/src/styles/scrollbar.css +47 -0
- flock/frontend/src/styles/variables.css +488 -0
- flock/frontend/src/test/setup.ts +1 -0
- flock/frontend/src/types/filters.ts +47 -0
- flock/frontend/src/types/graph.ts +95 -0
- flock/frontend/src/types/modules.ts +10 -0
- flock/frontend/src/types/theme.ts +55 -0
- flock/frontend/src/utils/artifacts.ts +24 -0
- flock/frontend/src/utils/mockData.ts +98 -0
- flock/frontend/src/utils/performance.ts +16 -0
- flock/frontend/src/vite-env.d.ts +17 -0
- flock/frontend/tsconfig.json +27 -0
- flock/frontend/tsconfig.node.json +11 -0
- flock/frontend/vite.config.ts +25 -0
- flock/frontend/vitest.config.ts +11 -0
- flock/{core/util → helper}/cli_helper.py +9 -5
- flock/{core/logging → logging}/__init__.py +2 -3
- flock/logging/auto_trace.py +159 -0
- 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 -107
- flock/{core/logging → logging}/logging.py +78 -61
- flock/{core/logging → logging}/telemetry.py +66 -26
- flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
- flock/logging/telemetry_exporter/duckdb_exporter.py +216 -0
- flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +13 -10
- flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
- flock/logging/trace_and_logged.py +304 -0
- flock/mcp/__init__.py +91 -0
- flock/{core/mcp/mcp_client.py → mcp/client.py} +131 -158
- flock/{core/mcp/mcp_config.py → mcp/config.py} +86 -132
- flock/mcp/manager.py +286 -0
- flock/mcp/servers/sse/__init__.py +1 -1
- flock/mcp/servers/sse/flock_sse_server.py +16 -58
- flock/mcp/servers/stdio/__init__.py +1 -1
- flock/mcp/servers/stdio/flock_stdio_server.py +13 -53
- flock/mcp/servers/streamable_http/flock_streamable_http_server.py +22 -67
- flock/mcp/servers/websockets/flock_websocket_server.py +12 -45
- flock/{core/mcp/flock_mcp_tool_base.py → mcp/tool.py} +24 -78
- flock/mcp/types/__init__.py +42 -0
- flock/{core/mcp → mcp}/types/callbacks.py +12 -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 +3 -3
- flock/orchestrator.py +970 -0
- flock/registry.py +148 -0
- flock/runtime.py +262 -0
- flock/service.py +277 -0
- flock/store.py +1214 -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/darkmatrix.toml +2 -2
- flock/themes/darkside.toml +1 -1
- flock/themes/deep.toml +2 -2
- 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 +5 -5
- 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/utility/output_utility_component.py +226 -0
- flock/visibility.py +107 -0
- flock_core-0.5.0.dist-info/METADATA +964 -0
- flock_core-0.5.0.dist-info/RECORD +525 -0
- flock_core-0.5.0.dist-info/entry_points.txt +2 -0
- {flock_core-0.4.542.dist-info → flock_core-0.5.0.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/config.py +0 -56
- flock/core/__init__.py +0 -44
- flock/core/api/__init__.py +0 -10
- flock/core/api/custom_endpoint.py +0 -45
- flock/core/api/endpoints.py +0 -262
- flock/core/api/main.py +0 -162
- flock/core/api/models.py +0 -101
- flock/core/api/run_store.py +0 -224
- flock/core/api/runner.py +0 -44
- flock/core/api/service.py +0 -214
- flock/core/config/flock_agent_config.py +0 -11
- flock/core/config/scheduled_agent_config.py +0 -40
- flock/core/context/context.py +0 -214
- flock/core/context/context_manager.py +0 -40
- flock/core/context/context_vars.py +0 -11
- flock/core/evaluation/utils.py +0 -395
- 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 -166
- flock/core/flock.py +0 -1003
- flock/core/flock_agent.py +0 -1258
- flock/core/flock_evaluator.py +0 -60
- flock/core/flock_factory.py +0 -513
- flock/core/flock_module.py +0 -207
- flock/core/flock_registry.py +0 -702
- flock/core/flock_router.py +0 -83
- 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/logging/live_capture.py +0 -137
- flock/core/logging/trace_and_logged.py +0 -59
- flock/core/mcp/__init__.py +0 -1
- flock/core/mcp/flock_mcp_server.py +0 -640
- flock/core/mcp/mcp_client_manager.py +0 -201
- flock/core/mcp/types/__init__.py +0 -1
- flock/core/mixin/dspy_integration.py +0 -445
- flock/core/mixin/prompt_parser.py +0 -125
- flock/core/serialization/__init__.py +0 -13
- flock/core/serialization/callable_registry.py +0 -52
- flock/core/serialization/flock_serializer.py +0 -854
- 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 -409
- flock/core/util/file_path_utils.py +0 -223
- flock/core/util/hydrator.py +0 -309
- flock/core/util/input_resolver.py +0 -141
- flock/core/util/loader.py +0 -59
- flock/core/util/splitter.py +0 -219
- flock/di.py +0 -41
- flock/evaluators/__init__.py +0 -1
- flock/evaluators/declarative/__init__.py +0 -1
- flock/evaluators/declarative/declarative_evaluator.py +0 -217
- flock/evaluators/memory/memory_evaluator.py +0 -90
- flock/evaluators/test/test_case_evaluator.py +0 -38
- flock/evaluators/zep/zep_evaluator.py +0 -59
- flock/modules/__init__.py +0 -1
- flock/modules/assertion/__init__.py +0 -1
- flock/modules/assertion/assertion_module.py +0 -286
- flock/modules/callback/__init__.py +0 -1
- flock/modules/callback/callback_module.py +0 -91
- flock/modules/enterprise_memory/README.md +0 -99
- flock/modules/enterprise_memory/enterprise_memory_module.py +0 -526
- flock/modules/mem0/__init__.py +0 -1
- flock/modules/mem0/mem0_module.py +0 -126
- flock/modules/mem0_async/__init__.py +0 -1
- flock/modules/mem0_async/async_mem0_module.py +0 -126
- flock/modules/memory/__init__.py +0 -1
- flock/modules/memory/memory_module.py +0 -429
- flock/modules/memory/memory_parser.py +0 -125
- flock/modules/memory/memory_storage.py +0 -736
- flock/modules/output/__init__.py +0 -1
- flock/modules/output/output_module.py +0 -196
- flock/modules/performance/__init__.py +0 -1
- flock/modules/performance/metrics_module.py +0 -678
- flock/modules/zep/__init__.py +0 -1
- flock/modules/zep/zep_module.py +0 -192
- flock/platform/docker_tools.py +0 -49
- flock/platform/jaeger_install.py +0 -86
- flock/routers/__init__.py +0 -1
- flock/routers/agent/__init__.py +0 -1
- flock/routers/agent/agent_router.py +0 -236
- flock/routers/agent/handoff_agent.py +0 -58
- flock/routers/conditional/conditional_router.py +0 -486
- flock/routers/default/__init__.py +0 -1
- flock/routers/default/default_router.py +0 -80
- flock/routers/feedback/feedback_router.py +0 -114
- flock/routers/list_generator/list_generator_router.py +0 -166
- flock/routers/llm/__init__.py +0 -1
- flock/routers/llm/llm_router.py +0 -365
- flock/tools/__init__.py +0 -0
- flock/tools/azure_tools.py +0 -781
- flock/tools/code_tools.py +0 -167
- flock/tools/file_tools.py +0 -149
- flock/tools/github_tools.py +0 -157
- flock/tools/markdown_tools.py +0 -205
- flock/tools/system_tools.py +0 -9
- flock/tools/text_tools.py +0 -810
- flock/tools/web_tools.py +0 -92
- flock/tools/zendesk_tools.py +0 -501
- 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 -237
- flock/webapp/app/api/execution.py +0 -503
- flock/webapp/app/api/flock_management.py +0 -125
- flock/webapp/app/api/registry_viewer.py +0 -29
- flock/webapp/app/chat.py +0 -662
- flock/webapp/app/config.py +0 -104
- flock/webapp/app/dependencies.py +0 -117
- flock/webapp/app/main.py +0 -1086
- 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 -345
- flock/webapp/app/services/sharing_models.py +0 -81
- flock/webapp/app/services/sharing_store.py +0 -597
- flock/webapp/app/templates/theme_mapper.html +0 -326
- flock/webapp/app/theme_mapper.py +0 -811
- flock/webapp/app/utils.py +0 -85
- flock/webapp/run.py +0 -219
- 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 -281
- flock/webapp/static/css/sidebar.css +0 -127
- flock/webapp/static/css/two-pane.css +0 -48
- flock/webapp/templates/base.html +0 -389
- 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 -127
- 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/_live_logs.html +0 -13
- 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/_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 -237
- flock/workflow/agent_activities.py +0 -24
- flock/workflow/agent_execution_activity.py +0 -240
- flock/workflow/flock_workflow.py +0 -225
- flock/workflow/temporal_config.py +0 -96
- flock/workflow/temporal_setup.py +0 -60
- flock_core-0.4.542.dist-info/METADATA +0 -676
- flock_core-0.4.542.dist-info/RECORD +0 -572
- flock_core-0.4.542.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.4.542.dist-info → flock_core-0.5.0.dist-info}/WHEEL +0 -0
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
"""Manages a pool of connections for a particular server."""
|
|
2
|
-
|
|
3
|
-
import copy
|
|
4
|
-
from abc import ABC, abstractmethod
|
|
5
|
-
from asyncio import Lock
|
|
6
|
-
from typing import Any, Generic, TypeVar
|
|
7
|
-
|
|
8
|
-
from opentelemetry import trace
|
|
9
|
-
from pydantic import (
|
|
10
|
-
BaseModel,
|
|
11
|
-
ConfigDict,
|
|
12
|
-
Field,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
from flock.core.logging.logging import get_logger
|
|
16
|
-
from flock.core.mcp.flock_mcp_tool_base import FlockMCPToolBase
|
|
17
|
-
from flock.core.mcp.mcp_client import (
|
|
18
|
-
FlockMCPClientBase,
|
|
19
|
-
)
|
|
20
|
-
from flock.core.mcp.mcp_config import FlockMCPConfigurationBase
|
|
21
|
-
|
|
22
|
-
logger = get_logger("mcp.client_manager")
|
|
23
|
-
tracer = trace.get_tracer(__name__)
|
|
24
|
-
|
|
25
|
-
TClient = TypeVar("TClient", bound="FlockMCPClientBase")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class FlockMCPClientManagerBase(BaseModel, ABC, Generic[TClient]):
|
|
29
|
-
"""Handles a Pool of MCPClients of type TClient."""
|
|
30
|
-
|
|
31
|
-
client_config: FlockMCPConfigurationBase = Field(
|
|
32
|
-
..., description="Configuration for clients."
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
lock: Lock = Field(
|
|
36
|
-
default_factory=Lock,
|
|
37
|
-
description="Lock for mutex access.",
|
|
38
|
-
exclude=True,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
clients: dict[str, dict[str, FlockMCPClientBase]] = Field(
|
|
42
|
-
default_factory=dict,
|
|
43
|
-
exclude=True,
|
|
44
|
-
description="Internal Store for the clients.",
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
# --- Pydantic v2 Configuratioin ---
|
|
48
|
-
model_config = ConfigDict(
|
|
49
|
-
arbitrary_types_allowed=True,
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
@abstractmethod
|
|
53
|
-
async def make_client(
|
|
54
|
-
self,
|
|
55
|
-
additional_params: dict[str, Any] | None = None,
|
|
56
|
-
) -> type[TClient]:
|
|
57
|
-
"""Instantiate-but don't connect yet-a fresh client of the concrete subtype."""
|
|
58
|
-
# default implementation
|
|
59
|
-
pass
|
|
60
|
-
|
|
61
|
-
async def get_client(
|
|
62
|
-
self,
|
|
63
|
-
agent_id: str,
|
|
64
|
-
run_id: str,
|
|
65
|
-
additional_params: dict[str, Any] | None = None,
|
|
66
|
-
) -> type[TClient]:
|
|
67
|
-
"""Provides a client from the pool."""
|
|
68
|
-
# Attempt to get a client from the client store.
|
|
69
|
-
# clients are stored like this: agent_id -> run_id -> client
|
|
70
|
-
with tracer.start_as_current_span("client_manager.get_client") as span:
|
|
71
|
-
span.set_attribute("agent_id", agent_id)
|
|
72
|
-
span.set_attribute("run_id", run_id)
|
|
73
|
-
async with self.lock:
|
|
74
|
-
try:
|
|
75
|
-
logger.debug(
|
|
76
|
-
f"Attempting to get client for server '{self.client_config.name}'"
|
|
77
|
-
)
|
|
78
|
-
refresh = False
|
|
79
|
-
if additional_params:
|
|
80
|
-
refresh = bool(
|
|
81
|
-
additional_params.get("refresh_client", False)
|
|
82
|
-
)
|
|
83
|
-
client = None
|
|
84
|
-
run_clients = self.clients.get(agent_id, None)
|
|
85
|
-
if run_clients is None or refresh:
|
|
86
|
-
# This means, that across all runs, no agent has ever needed a client.
|
|
87
|
-
# This also means that we need to create a client.
|
|
88
|
-
client = await self.make_client(
|
|
89
|
-
additional_params=copy.deepcopy(additional_params)
|
|
90
|
-
)
|
|
91
|
-
# Insert the freshly created client
|
|
92
|
-
self.clients[agent_id] = {}
|
|
93
|
-
self.clients[agent_id][run_id] = client
|
|
94
|
-
|
|
95
|
-
else:
|
|
96
|
-
# This means there is at least one entry for the agent_id available
|
|
97
|
-
# Now, all we need to do is check if the run_id matches the entrie's run_id
|
|
98
|
-
client = run_clients.get(run_id, None)
|
|
99
|
-
if client is None or refresh:
|
|
100
|
-
# Means no client here with the respective run_id
|
|
101
|
-
client = await self.make_client(
|
|
102
|
-
additional_params=copy.deepcopy(
|
|
103
|
-
additional_params
|
|
104
|
-
)
|
|
105
|
-
)
|
|
106
|
-
# Insert the freshly created client.
|
|
107
|
-
self.clients[agent_id][run_id] = client
|
|
108
|
-
|
|
109
|
-
return client
|
|
110
|
-
except Exception as e:
|
|
111
|
-
# Log the exception and raise it so it becomes visible downstream
|
|
112
|
-
logger.error(
|
|
113
|
-
f"Unexpected Exception ocurred while trying to get client for server '{self.client_config.name}' with agent_id: {agent_id} and run_id: {run_id}: {e}"
|
|
114
|
-
)
|
|
115
|
-
span.record_exception(e)
|
|
116
|
-
raise e
|
|
117
|
-
|
|
118
|
-
async def call_tool(
|
|
119
|
-
self,
|
|
120
|
-
agent_id: str,
|
|
121
|
-
run_id: str,
|
|
122
|
-
name: str,
|
|
123
|
-
arguments: dict[str, Any],
|
|
124
|
-
additional_params: dict[str, Any] | None = None,
|
|
125
|
-
) -> Any:
|
|
126
|
-
"""Call a tool."""
|
|
127
|
-
with tracer.start_as_current_span("client_manager.call_tool") as span:
|
|
128
|
-
span.set_attribute("agent_id", agent_id)
|
|
129
|
-
span.set_attribute("run_id", run_id)
|
|
130
|
-
span.set_attribute("tool_name", name)
|
|
131
|
-
span.set_attribute("arguments", str(arguments))
|
|
132
|
-
try:
|
|
133
|
-
client = await self.get_client(
|
|
134
|
-
agent_id=agent_id,
|
|
135
|
-
run_id=run_id,
|
|
136
|
-
additional_params=additional_params,
|
|
137
|
-
)
|
|
138
|
-
result = await client.call_tool(
|
|
139
|
-
agent_id=agent_id,
|
|
140
|
-
run_id=run_id,
|
|
141
|
-
name=name,
|
|
142
|
-
arguments=arguments,
|
|
143
|
-
)
|
|
144
|
-
return result
|
|
145
|
-
except Exception as e:
|
|
146
|
-
logger.error(
|
|
147
|
-
f"Exception occurred while trying to call tool {name} on server '{self.client_config.name}': {e}"
|
|
148
|
-
)
|
|
149
|
-
span.record_exception(e)
|
|
150
|
-
return None
|
|
151
|
-
|
|
152
|
-
async def get_tools(
|
|
153
|
-
self,
|
|
154
|
-
agent_id: str,
|
|
155
|
-
run_id: str,
|
|
156
|
-
additional_params: dict[str, Any] | None = None,
|
|
157
|
-
) -> list[FlockMCPToolBase]:
|
|
158
|
-
"""Retrieves a list of tools for the agents to act on."""
|
|
159
|
-
with tracer.start_as_current_span("client_manager.get_tools") as span:
|
|
160
|
-
span.set_attribute("agent_id", agent_id)
|
|
161
|
-
span.set_attribute("run_id", run_id)
|
|
162
|
-
try:
|
|
163
|
-
client = await self.get_client(
|
|
164
|
-
agent_id=agent_id,
|
|
165
|
-
run_id=run_id,
|
|
166
|
-
additional_params=additional_params,
|
|
167
|
-
)
|
|
168
|
-
tools: list[FlockMCPToolBase] = await client.get_tools(
|
|
169
|
-
agent_id=agent_id, run_id=run_id
|
|
170
|
-
)
|
|
171
|
-
return tools
|
|
172
|
-
except Exception as e:
|
|
173
|
-
logger.error(
|
|
174
|
-
f"Exception occurred while trying to retrieve Tools for server '{self.client_config.name}' with agent_id: {agent_id} and run_id: {run_id}: {e}"
|
|
175
|
-
)
|
|
176
|
-
span.record_exception(e)
|
|
177
|
-
return []
|
|
178
|
-
|
|
179
|
-
async def close_all(self) -> None:
|
|
180
|
-
"""Closes all connections in the pool and cancels background tasks."""
|
|
181
|
-
with tracer.start_as_current_span("client_manager.close_all") as span:
|
|
182
|
-
async with self.lock:
|
|
183
|
-
for agent_id, run_dict in self.clients.items():
|
|
184
|
-
logger.debug(
|
|
185
|
-
f"Shutting down all clients for agent_id: {agent_id}"
|
|
186
|
-
)
|
|
187
|
-
for run_id, client in run_dict.items():
|
|
188
|
-
logger.debug(
|
|
189
|
-
f"Shutting down client for agent_id {agent_id} and run_id {run_id}"
|
|
190
|
-
)
|
|
191
|
-
try:
|
|
192
|
-
await client.disconnect()
|
|
193
|
-
except Exception as e:
|
|
194
|
-
logger.error(
|
|
195
|
-
f"Error when trying to disconnect client for server '{self.client_config.name}': {e}"
|
|
196
|
-
)
|
|
197
|
-
span.record_exception(e)
|
|
198
|
-
self.clients = {} # Let the GC take care of the rest.
|
|
199
|
-
logger.info(
|
|
200
|
-
f"All clients disconnected for server '{self.client_config.name}'"
|
|
201
|
-
)
|
flock/core/mcp/types/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"""MCP Types package."""
|
|
@@ -1,445 +0,0 @@
|
|
|
1
|
-
# src/flock/core/mixin/dspy_integration.py
|
|
2
|
-
"""Mixin class for integrating with the dspy library."""
|
|
3
|
-
|
|
4
|
-
import ast
|
|
5
|
-
import re # Import re for parsing
|
|
6
|
-
import typing
|
|
7
|
-
from typing import Any, Literal
|
|
8
|
-
|
|
9
|
-
from dspy import Tool
|
|
10
|
-
|
|
11
|
-
from flock.core.logging.logging import get_logger
|
|
12
|
-
from flock.core.util.splitter import split_top_level
|
|
13
|
-
|
|
14
|
-
# Import split_top_level (assuming it's moved or copied appropriately)
|
|
15
|
-
# Option 1: If moved to a shared util
|
|
16
|
-
# from flock.core.util.parsing_utils import split_top_level
|
|
17
|
-
# Option 2: If kept within this file (as in previous example)
|
|
18
|
-
# Define split_top_level here or ensure it's imported
|
|
19
|
-
|
|
20
|
-
logger = get_logger("mixin.dspy")
|
|
21
|
-
|
|
22
|
-
# Type definition for agent type override
|
|
23
|
-
AgentType = Literal["ReAct", "Completion", "ChainOfThought"] | None
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# Helper function to resolve type strings (can be static or module-level)
|
|
27
|
-
def _resolve_type_string(type_str: str) -> type:
|
|
28
|
-
"""Resolves a type string into a Python type object.
|
|
29
|
-
Handles built-ins, registered types, and common typing generics like
|
|
30
|
-
List, Dict, Optional, Union, Literal.
|
|
31
|
-
"""
|
|
32
|
-
# Import registry here to avoid circular imports
|
|
33
|
-
from flock.core.flock_registry import get_registry
|
|
34
|
-
|
|
35
|
-
FlockRegistry = get_registry()
|
|
36
|
-
|
|
37
|
-
type_str = type_str.strip()
|
|
38
|
-
logger.debug(f"Attempting to resolve type string: '{type_str}'")
|
|
39
|
-
|
|
40
|
-
# 1. Check built-ins and registered types directly
|
|
41
|
-
try:
|
|
42
|
-
# This covers str, int, bool, Any, and types registered by name
|
|
43
|
-
resolved_type = FlockRegistry.get_type(type_str)
|
|
44
|
-
logger.debug(f"Resolved '{type_str}' via registry to: {resolved_type}")
|
|
45
|
-
return resolved_type
|
|
46
|
-
except KeyError:
|
|
47
|
-
logger.debug(
|
|
48
|
-
f"'{type_str}' not found directly in registry, attempting generic parsing."
|
|
49
|
-
)
|
|
50
|
-
pass # Not found, continue parsing generics
|
|
51
|
-
|
|
52
|
-
# 2. Handle typing generics (List, Dict, Optional, Union, Literal)
|
|
53
|
-
# Use regex to match pattern like Generic[InnerType1, InnerType2, ...]
|
|
54
|
-
generic_match = re.fullmatch(r"(\w+)\s*\[(.*)\]", type_str)
|
|
55
|
-
if generic_match:
|
|
56
|
-
base_name = generic_match.group(1).strip()
|
|
57
|
-
args_str = generic_match.group(2).strip()
|
|
58
|
-
logger.debug(
|
|
59
|
-
f"Detected generic pattern: Base='{base_name}', Args='{args_str}'"
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
try:
|
|
63
|
-
# Get the base generic type (e.g., list, dict, Optional) from registry/builtins
|
|
64
|
-
BaseType = FlockRegistry.get_type(
|
|
65
|
-
base_name
|
|
66
|
-
) # Expects List, Dict etc. to be registered
|
|
67
|
-
logger.debug(
|
|
68
|
-
f"Resolved base generic type '{base_name}' to: {BaseType}"
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
# Special handling for Literal
|
|
72
|
-
if BaseType is typing.Literal:
|
|
73
|
-
# Split literal values, remove quotes, strip whitespace
|
|
74
|
-
def parse_literal_args(args_str: str) -> tuple[str, ...]:
|
|
75
|
-
try:
|
|
76
|
-
return tuple(ast.literal_eval(f"[{args_str}]"))
|
|
77
|
-
except (SyntaxError, ValueError) as exc:
|
|
78
|
-
raise ValueError(
|
|
79
|
-
f"Cannot parse {args_str!r} as literals"
|
|
80
|
-
) from exc
|
|
81
|
-
|
|
82
|
-
literal_args = parse_literal_args(args_str)
|
|
83
|
-
logger.debug(
|
|
84
|
-
f"Parsing Literal arguments: {args_str} -> {literal_args}"
|
|
85
|
-
)
|
|
86
|
-
resolved_type = typing.Literal[literal_args] # type: ignore
|
|
87
|
-
logger.debug(f"Constructed Literal type: {resolved_type}")
|
|
88
|
-
return resolved_type
|
|
89
|
-
|
|
90
|
-
# Recursively resolve arguments for other generics
|
|
91
|
-
logger.debug(f"Splitting generic arguments: '{args_str}'")
|
|
92
|
-
arg_strs = split_top_level(args_str)
|
|
93
|
-
logger.debug(f"Split arguments: {arg_strs}")
|
|
94
|
-
if not arg_strs:
|
|
95
|
-
raise ValueError("Generic type has no arguments.")
|
|
96
|
-
|
|
97
|
-
resolved_arg_types = tuple(
|
|
98
|
-
_resolve_type_string(arg) for arg in arg_strs
|
|
99
|
-
)
|
|
100
|
-
logger.debug(f"Resolved generic arguments: {resolved_arg_types}")
|
|
101
|
-
|
|
102
|
-
# Construct the generic type hint
|
|
103
|
-
if BaseType is typing.Optional:
|
|
104
|
-
if len(resolved_arg_types) != 1:
|
|
105
|
-
raise ValueError("Optional requires exactly one argument.")
|
|
106
|
-
# type: ignore
|
|
107
|
-
resolved_type = typing.Union[resolved_arg_types[0], type(None)]
|
|
108
|
-
logger.debug(
|
|
109
|
-
f"Constructed Optional type as Union: {resolved_type}"
|
|
110
|
-
)
|
|
111
|
-
return resolved_type
|
|
112
|
-
elif BaseType is typing.Union:
|
|
113
|
-
if not resolved_arg_types:
|
|
114
|
-
raise ValueError("Union requires at least one argument.")
|
|
115
|
-
# type: ignore
|
|
116
|
-
resolved_type = typing.Union[resolved_arg_types]
|
|
117
|
-
logger.debug(f"Constructed Union type: {resolved_type}")
|
|
118
|
-
return resolved_type
|
|
119
|
-
elif hasattr(
|
|
120
|
-
BaseType, "__getitem__"
|
|
121
|
-
): # Check if subscriptable (like list, dict, List, Dict)
|
|
122
|
-
resolved_type = BaseType[resolved_arg_types] # type: ignore
|
|
123
|
-
logger.debug(
|
|
124
|
-
f"Constructed subscripted generic type: {resolved_type}"
|
|
125
|
-
)
|
|
126
|
-
return resolved_type
|
|
127
|
-
else:
|
|
128
|
-
# Base type found but cannot be subscripted
|
|
129
|
-
logger.warning(
|
|
130
|
-
f"Base type '{base_name}' found but is not a standard subscriptable generic. Returning base type."
|
|
131
|
-
)
|
|
132
|
-
return BaseType
|
|
133
|
-
|
|
134
|
-
except (KeyError, ValueError, IndexError, TypeError) as e:
|
|
135
|
-
logger.warning(
|
|
136
|
-
f"Failed to parse generic type '{type_str}': {e}. Falling back."
|
|
137
|
-
)
|
|
138
|
-
# Fall through to raise KeyError below if base type itself wasn't found or parsing failed
|
|
139
|
-
|
|
140
|
-
# 3. If not resolved by now, raise error
|
|
141
|
-
logger.error(f"Type string '{type_str}' could not be resolved.")
|
|
142
|
-
raise KeyError(f"Type '{type_str}' could not be resolved.")
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
class DSPyIntegrationMixin:
|
|
146
|
-
"""Mixin class for integrating with the dspy library."""
|
|
147
|
-
|
|
148
|
-
def create_dspy_signature_class(
|
|
149
|
-
self, agent_name, description_spec, fields_spec
|
|
150
|
-
) -> Any:
|
|
151
|
-
"""Creates a dynamic DSPy Signature class from string specifications,
|
|
152
|
-
resolving types using the FlockRegistry.
|
|
153
|
-
"""
|
|
154
|
-
try:
|
|
155
|
-
import dspy
|
|
156
|
-
except ImportError:
|
|
157
|
-
logger.error(
|
|
158
|
-
"DSPy library is not installed. Cannot create DSPy signature. "
|
|
159
|
-
"Install with: pip install dspy-ai"
|
|
160
|
-
)
|
|
161
|
-
raise ImportError("DSPy is required for this functionality.")
|
|
162
|
-
|
|
163
|
-
base_class = dspy.Signature
|
|
164
|
-
class_dict = {"__doc__": description_spec, "__annotations__": {}}
|
|
165
|
-
|
|
166
|
-
if "->" in fields_spec:
|
|
167
|
-
inputs_spec, outputs_spec = fields_spec.split("->", 1)
|
|
168
|
-
else:
|
|
169
|
-
inputs_spec, outputs_spec = (
|
|
170
|
-
fields_spec,
|
|
171
|
-
"",
|
|
172
|
-
) # Assume only inputs if no '->'
|
|
173
|
-
|
|
174
|
-
def parse_field(field_str):
|
|
175
|
-
"""Parses 'name: type_str | description' using _resolve_type_string."""
|
|
176
|
-
field_str = field_str.strip()
|
|
177
|
-
if not field_str:
|
|
178
|
-
return None
|
|
179
|
-
|
|
180
|
-
parts = field_str.split("|", 1)
|
|
181
|
-
main_part = parts[0].strip()
|
|
182
|
-
desc = parts[1].strip() if len(parts) > 1 else None
|
|
183
|
-
|
|
184
|
-
if ":" in main_part:
|
|
185
|
-
name, type_str = [s.strip() for s in main_part.split(":", 1)]
|
|
186
|
-
else:
|
|
187
|
-
name = main_part
|
|
188
|
-
type_str = "str" # Default type
|
|
189
|
-
|
|
190
|
-
try:
|
|
191
|
-
field_type = _resolve_type_string(type_str)
|
|
192
|
-
except Exception as e: # Catch resolution errors
|
|
193
|
-
logger.error(
|
|
194
|
-
f"Failed to resolve type '{type_str}' for field '{name}': {e}. Defaulting to str."
|
|
195
|
-
)
|
|
196
|
-
field_type = str
|
|
197
|
-
|
|
198
|
-
return name, field_type, desc
|
|
199
|
-
|
|
200
|
-
def process_fields(fields_string, field_kind):
|
|
201
|
-
"""Process fields and add to class_dict."""
|
|
202
|
-
if not fields_string or not fields_string.strip():
|
|
203
|
-
return
|
|
204
|
-
|
|
205
|
-
split_fields = split_top_level(fields_string)
|
|
206
|
-
for field in split_fields:
|
|
207
|
-
if field.strip():
|
|
208
|
-
parsed = parse_field(field)
|
|
209
|
-
if not parsed:
|
|
210
|
-
continue
|
|
211
|
-
name, field_type, desc = parsed
|
|
212
|
-
class_dict["__annotations__"][name] = (
|
|
213
|
-
field_type # Use resolved type
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
FieldClass = (
|
|
217
|
-
dspy.InputField
|
|
218
|
-
if field_kind == "input"
|
|
219
|
-
else dspy.OutputField
|
|
220
|
-
)
|
|
221
|
-
# DSPy Fields use 'desc' for description
|
|
222
|
-
class_dict[name] = (
|
|
223
|
-
FieldClass(desc=desc)
|
|
224
|
-
if desc is not None
|
|
225
|
-
else FieldClass()
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
try:
|
|
229
|
-
process_fields(inputs_spec, "input")
|
|
230
|
-
process_fields(outputs_spec, "output")
|
|
231
|
-
except Exception as e:
|
|
232
|
-
logger.error(
|
|
233
|
-
f"Error processing fields for DSPy signature '{agent_name}': {e}",
|
|
234
|
-
exc_info=True,
|
|
235
|
-
)
|
|
236
|
-
raise ValueError(
|
|
237
|
-
f"Could not process fields for signature: {e}"
|
|
238
|
-
) from e
|
|
239
|
-
|
|
240
|
-
# Create and return the dynamic class
|
|
241
|
-
try:
|
|
242
|
-
DynamicSignature = type(
|
|
243
|
-
"dspy_" + agent_name, (base_class,), class_dict
|
|
244
|
-
)
|
|
245
|
-
logger.info(
|
|
246
|
-
f"Successfully created DSPy Signature: {DynamicSignature.__name__} "
|
|
247
|
-
f"with fields: {DynamicSignature.__annotations__}"
|
|
248
|
-
)
|
|
249
|
-
return DynamicSignature
|
|
250
|
-
except Exception as e:
|
|
251
|
-
logger.error(
|
|
252
|
-
f"Failed to create dynamic type 'dspy_{agent_name}': {e}",
|
|
253
|
-
exc_info=True,
|
|
254
|
-
)
|
|
255
|
-
raise TypeError(f"Could not create DSPy signature type: {e}") from e
|
|
256
|
-
|
|
257
|
-
def _configure_language_model(
|
|
258
|
-
self,
|
|
259
|
-
model: str | None,
|
|
260
|
-
use_cache: bool,
|
|
261
|
-
temperature: float,
|
|
262
|
-
max_tokens: int,
|
|
263
|
-
) -> None:
|
|
264
|
-
"""Initialize and configure the language model using dspy."""
|
|
265
|
-
if model is None:
|
|
266
|
-
logger.warning(
|
|
267
|
-
"No model specified for DSPy configuration. Using DSPy default."
|
|
268
|
-
)
|
|
269
|
-
# Rely on DSPy's global default or raise error if none configured
|
|
270
|
-
# import dspy
|
|
271
|
-
# if dspy.settings.lm is None:
|
|
272
|
-
# raise ValueError("No model specified for agent and no global DSPy LM configured.")
|
|
273
|
-
return
|
|
274
|
-
|
|
275
|
-
try:
|
|
276
|
-
import dspy
|
|
277
|
-
except ImportError:
|
|
278
|
-
logger.error(
|
|
279
|
-
"DSPy library is not installed. Cannot configure language model."
|
|
280
|
-
)
|
|
281
|
-
return # Or raise
|
|
282
|
-
|
|
283
|
-
try:
|
|
284
|
-
# Ensure 'cache' parameter is handled correctly (might not exist on dspy.LM directly)
|
|
285
|
-
# DSPy handles caching globally or via specific optimizers typically.
|
|
286
|
-
# We'll configure the LM without explicit cache control here.
|
|
287
|
-
lm_instance = dspy.LM(
|
|
288
|
-
model=model,
|
|
289
|
-
temperature=temperature,
|
|
290
|
-
max_tokens=max_tokens,
|
|
291
|
-
cache=use_cache,
|
|
292
|
-
# Add other relevant parameters if needed, e.g., API keys via dspy.settings
|
|
293
|
-
)
|
|
294
|
-
dspy.settings.configure(lm=lm_instance)
|
|
295
|
-
logger.info(
|
|
296
|
-
f"DSPy LM configured with model: {model}, temp: {temperature}, max_tokens: {max_tokens}"
|
|
297
|
-
)
|
|
298
|
-
# Note: DSPy caching is usually configured globally, e.g., dspy.settings.configure(cache=...)
|
|
299
|
-
# or handled by optimizers. Setting `cache=use_cache` on dspy.LM might not be standard.
|
|
300
|
-
except Exception as e:
|
|
301
|
-
logger.error(
|
|
302
|
-
f"Failed to configure DSPy language model '{model}': {e}",
|
|
303
|
-
exc_info=True,
|
|
304
|
-
)
|
|
305
|
-
# We need to raise this exception, otherwise Flock will trundle on until it needs dspy.settings.lm and can't find it.
|
|
306
|
-
raise
|
|
307
|
-
|
|
308
|
-
def _select_task(
|
|
309
|
-
self,
|
|
310
|
-
signature: Any,
|
|
311
|
-
override_evaluator_type: AgentType,
|
|
312
|
-
max_tool_calls: int = 10,
|
|
313
|
-
tools: list[Any] | None = None,
|
|
314
|
-
mcp_tools: list[Any] | None = None,
|
|
315
|
-
kwargs: dict[str, Any] = {},
|
|
316
|
-
) -> Any:
|
|
317
|
-
"""Select and instantiate the appropriate DSPy Program/Module."""
|
|
318
|
-
try:
|
|
319
|
-
import dspy
|
|
320
|
-
except ImportError:
|
|
321
|
-
logger.error(
|
|
322
|
-
"DSPy library is not installed. Cannot select DSPy task."
|
|
323
|
-
)
|
|
324
|
-
raise ImportError("DSPy is required for this functionality.")
|
|
325
|
-
|
|
326
|
-
processed_tools = []
|
|
327
|
-
if tools:
|
|
328
|
-
for tool in tools:
|
|
329
|
-
if callable(tool): # Basic check
|
|
330
|
-
processed_tools.append(tool)
|
|
331
|
-
# Could add more sophisticated tool wrapping/validation here if needed
|
|
332
|
-
else:
|
|
333
|
-
logger.warning(
|
|
334
|
-
f"Item '{tool}' in tools list is not callable, skipping."
|
|
335
|
-
)
|
|
336
|
-
|
|
337
|
-
processed_mcp_tools = []
|
|
338
|
-
if mcp_tools:
|
|
339
|
-
for mcp_tool in mcp_tools:
|
|
340
|
-
if isinstance(mcp_tool, Tool): # Basic check
|
|
341
|
-
processed_mcp_tools.append(mcp_tool)
|
|
342
|
-
else:
|
|
343
|
-
logger.warning(
|
|
344
|
-
f"Item '{mcp_tool}' is not a dspy.primitives.Tool, skipping."
|
|
345
|
-
)
|
|
346
|
-
|
|
347
|
-
dspy_program = None
|
|
348
|
-
selected_type = override_evaluator_type
|
|
349
|
-
|
|
350
|
-
# Determine type if not overridden
|
|
351
|
-
if not selected_type:
|
|
352
|
-
selected_type = (
|
|
353
|
-
"ReAct" if processed_tools or processed_mcp_tools else "Predict"
|
|
354
|
-
) # Default logic
|
|
355
|
-
|
|
356
|
-
logger.debug(
|
|
357
|
-
f"Selecting DSPy program type: {selected_type} (Tools provided: {bool(processed_tools)}) (MCP Tools: {bool(processed_mcp_tools)}"
|
|
358
|
-
)
|
|
359
|
-
|
|
360
|
-
# Merge list of native tools and processed tools.
|
|
361
|
-
# This makes mcp tools appear as native code functions to the llm of the agent.
|
|
362
|
-
merged_tools = []
|
|
363
|
-
|
|
364
|
-
if processed_tools:
|
|
365
|
-
merged_tools = merged_tools + processed_tools
|
|
366
|
-
|
|
367
|
-
if processed_mcp_tools:
|
|
368
|
-
merged_tools = merged_tools + processed_mcp_tools
|
|
369
|
-
|
|
370
|
-
try:
|
|
371
|
-
if selected_type == "ChainOfThought":
|
|
372
|
-
dspy_program = dspy.ChainOfThought(signature, **kwargs)
|
|
373
|
-
elif selected_type == "ReAct":
|
|
374
|
-
if not kwargs:
|
|
375
|
-
kwargs = {"max_iters": max_tool_calls}
|
|
376
|
-
dspy_program = dspy.ReAct(
|
|
377
|
-
signature, tools=merged_tools or [], **kwargs
|
|
378
|
-
)
|
|
379
|
-
elif selected_type == "Predict": # Default or explicitly Completion
|
|
380
|
-
dspy_program = dspy.Predict(signature)
|
|
381
|
-
else: # Fallback or handle unknown type
|
|
382
|
-
logger.warning(
|
|
383
|
-
f"Unknown or unsupported agent_type_override '{selected_type}'. Defaulting to dspy.Predict."
|
|
384
|
-
)
|
|
385
|
-
dspy_program = dspy.Predict(signature)
|
|
386
|
-
|
|
387
|
-
logger.info(
|
|
388
|
-
f"Instantiated DSPy program: {type(dspy_program).__name__}"
|
|
389
|
-
)
|
|
390
|
-
return dspy_program
|
|
391
|
-
except Exception as e:
|
|
392
|
-
logger.error(
|
|
393
|
-
f"Failed to instantiate DSPy program of type '{selected_type}': {e}",
|
|
394
|
-
exc_info=True,
|
|
395
|
-
)
|
|
396
|
-
raise RuntimeError(f"Could not create DSPy program: {e}") from e
|
|
397
|
-
|
|
398
|
-
def _process_result(
|
|
399
|
-
self, result: Any, inputs: dict[str, Any]
|
|
400
|
-
) -> tuple[dict[str, Any], float, list]:
|
|
401
|
-
"""Convert the DSPy result object to a dictionary."""
|
|
402
|
-
import dspy
|
|
403
|
-
|
|
404
|
-
if result is None:
|
|
405
|
-
logger.warning("DSPy program returned None result.")
|
|
406
|
-
return {}
|
|
407
|
-
try:
|
|
408
|
-
# DSPy Prediction objects often behave like dicts or have .keys() / items()
|
|
409
|
-
if hasattr(result, "items") and callable(result.items):
|
|
410
|
-
output_dict = dict(result.items())
|
|
411
|
-
elif hasattr(result, "__dict__"): # Fallback for other object types
|
|
412
|
-
output_dict = {
|
|
413
|
-
k: v
|
|
414
|
-
for k, v in result.__dict__.items()
|
|
415
|
-
if not k.startswith("_")
|
|
416
|
-
}
|
|
417
|
-
else:
|
|
418
|
-
# If it's already a dict (less common for DSPy results directly)
|
|
419
|
-
if isinstance(result, dict):
|
|
420
|
-
output_dict = result
|
|
421
|
-
else: # Final fallback
|
|
422
|
-
logger.warning(
|
|
423
|
-
f"Could not reliably convert DSPy result of type {type(result)} to dict. Returning as is."
|
|
424
|
-
)
|
|
425
|
-
output_dict = {"raw_result": result}
|
|
426
|
-
|
|
427
|
-
logger.debug(f"Processed DSPy result to dict: {output_dict}")
|
|
428
|
-
# Optionally merge inputs back if desired (can make result dict large)
|
|
429
|
-
final_result = {**inputs, **output_dict}
|
|
430
|
-
|
|
431
|
-
lm = dspy.settings.get("lm")
|
|
432
|
-
cost = sum([x["cost"] for x in lm.history if x["cost"] is not None])
|
|
433
|
-
lm_history = lm.history
|
|
434
|
-
|
|
435
|
-
return final_result, cost, lm_history
|
|
436
|
-
|
|
437
|
-
except Exception as conv_error:
|
|
438
|
-
logger.error(
|
|
439
|
-
f"Failed to process DSPy result into dictionary: {conv_error}",
|
|
440
|
-
exc_info=True,
|
|
441
|
-
)
|
|
442
|
-
return {
|
|
443
|
-
"error": "Failed to process result",
|
|
444
|
-
"raw_result": str(result),
|
|
445
|
-
}
|