flock-core 0.4.543__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.543.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.543.dist-info/METADATA +0 -676
- flock_core-0.4.543.dist-info/RECORD +0 -572
- flock_core-0.4.543.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.543.dist-info → flock_core-0.5.0.dist-info}/WHEEL +0 -0
|
@@ -1,526 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
"""Enterprise-grade memory module for Flock.
|
|
4
|
-
|
|
5
|
-
This module persists:
|
|
6
|
-
• vector embeddings in a Chroma collection (or any collection that
|
|
7
|
-
implements the same API)
|
|
8
|
-
• a concept graph in Neo4j/Memgraph (Cypher-compatible)
|
|
9
|
-
|
|
10
|
-
It follows the same life-cycle callbacks as the standard MemoryModule but
|
|
11
|
-
is designed for large-scale, concurrent deployments.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
import asyncio
|
|
15
|
-
import json
|
|
16
|
-
import time
|
|
17
|
-
import uuid
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
from typing import Any, Literal
|
|
20
|
-
|
|
21
|
-
from neo4j import AsyncGraphDatabase
|
|
22
|
-
from opentelemetry import trace
|
|
23
|
-
from pydantic import Field
|
|
24
|
-
from sentence_transformers import SentenceTransformer
|
|
25
|
-
|
|
26
|
-
from flock.adapter.azure_adapter import AzureSearchAdapter
|
|
27
|
-
from flock.adapter.chroma_adapter import ChromaAdapter
|
|
28
|
-
from flock.adapter.faiss_adapter import FAISSAdapter
|
|
29
|
-
from flock.adapter.pinecone_adapter import PineconeAdapter
|
|
30
|
-
|
|
31
|
-
# Adapter imports
|
|
32
|
-
from flock.adapter.vector_base import VectorAdapter
|
|
33
|
-
from flock.core.context.context import FlockContext
|
|
34
|
-
from flock.core.flock_agent import FlockAgent
|
|
35
|
-
from flock.core.flock_module import FlockModule, FlockModuleConfig
|
|
36
|
-
from flock.core.flock_registry import flock_component
|
|
37
|
-
from flock.core.logging.logging import get_logger
|
|
38
|
-
from flock.modules.performance.metrics_module import MetricsModule
|
|
39
|
-
|
|
40
|
-
logger = get_logger("enterprise_memory")
|
|
41
|
-
tracer = trace.get_tracer(__name__)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
# ---------------------------------------------------------------------------
|
|
45
|
-
# Configuration
|
|
46
|
-
# ---------------------------------------------------------------------------
|
|
47
|
-
class EnterpriseMemoryModuleConfig(FlockModuleConfig):
|
|
48
|
-
"""Configuration for EnterpriseMemoryModule."""
|
|
49
|
-
|
|
50
|
-
# ---------------------
|
|
51
|
-
# Vector store settings
|
|
52
|
-
# ---------------------
|
|
53
|
-
|
|
54
|
-
vector_backend: Literal["chroma", "pinecone", "azure"] = Field(
|
|
55
|
-
default="chroma",
|
|
56
|
-
description="Which vector backend to use (chroma | pinecone | azure)",
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
# --- Chroma ---
|
|
60
|
-
chroma_path: str | None = Field(
|
|
61
|
-
default="./vector_store",
|
|
62
|
-
description="Disk path for Chroma persistent storage (if running embedded).",
|
|
63
|
-
)
|
|
64
|
-
chroma_collection: str = Field(
|
|
65
|
-
default="flock_memories", description="Chroma collection name"
|
|
66
|
-
)
|
|
67
|
-
chroma_host: str | None = Field(
|
|
68
|
-
default=None,
|
|
69
|
-
description="If provided, connect to a remote Chroma HTTP server at this host",
|
|
70
|
-
)
|
|
71
|
-
chroma_port: int = Field(default=8000, description="Remote Chroma HTTP port")
|
|
72
|
-
|
|
73
|
-
# --- Pinecone ---
|
|
74
|
-
pinecone_api_key: str | None = Field(default=None, description="Pinecone API key")
|
|
75
|
-
pinecone_env: str | None = Field(default=None, description="Pinecone environment")
|
|
76
|
-
pinecone_index: str | None = Field(default=None, description="Pinecone index name")
|
|
77
|
-
|
|
78
|
-
# --- Azure Cognitive Search ---
|
|
79
|
-
azure_search_endpoint: str | None = Field(default=None, description="Azure search endpoint (https://<service>.search.windows.net)")
|
|
80
|
-
azure_search_key: str | None = Field(default=None, description="Azure search admin/key")
|
|
81
|
-
azure_search_index_name: str | None = Field(default=None, description="Azure search index name")
|
|
82
|
-
|
|
83
|
-
# Graph DB (Neo4j / Memgraph) settings
|
|
84
|
-
cypher_uri: str = Field(
|
|
85
|
-
default="bolt://localhost:7687", description="Bolt URI for the graph DB"
|
|
86
|
-
)
|
|
87
|
-
cypher_username: str = Field(default="neo4j", description="Username for DB")
|
|
88
|
-
cypher_password: str = Field(default="password", description="Password for DB")
|
|
89
|
-
|
|
90
|
-
similarity_threshold: float = Field(
|
|
91
|
-
default=0.5, description="Cosine-similarity threshold for retrieval"
|
|
92
|
-
)
|
|
93
|
-
max_results: int = Field(default=10, description="Maximum retrieved memories")
|
|
94
|
-
number_of_concepts_to_extract: int = Field(
|
|
95
|
-
default=3, description="Number of concepts extracted per chunk"
|
|
96
|
-
)
|
|
97
|
-
save_interval: int = Field(
|
|
98
|
-
default=10,
|
|
99
|
-
description="Persist to disk after this many new chunks (0 disables auto-save)",
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
export_graph_image: bool = Field(
|
|
103
|
-
default=False,
|
|
104
|
-
description="If true, exports a PNG image of the concept graph each time it is updated.",
|
|
105
|
-
)
|
|
106
|
-
graph_image_dir: str = Field(
|
|
107
|
-
default="./concept_graphs",
|
|
108
|
-
description="Directory where graph images will be stored when export_graph_image is true.",
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
# ---------------------------------------------------------------------------
|
|
113
|
-
# Storage Abstraction
|
|
114
|
-
# ---------------------------------------------------------------------------
|
|
115
|
-
class EnterpriseMemoryStore:
|
|
116
|
-
"""Persistence layer that wraps Chroma + Cypher graph."""
|
|
117
|
-
|
|
118
|
-
def __init__(self, cfg: EnterpriseMemoryModuleConfig, metrics_module: MetricsModule | None = None):
|
|
119
|
-
self.cfg = cfg
|
|
120
|
-
# Metrics module (DI-resolved or fallback)
|
|
121
|
-
self._metrics = metrics_module or MetricsModule # can be either instance or class exposing .record
|
|
122
|
-
# Lazy initialise expensive resources
|
|
123
|
-
self._embedding_model: SentenceTransformer | None = None
|
|
124
|
-
self._adapter: VectorAdapter | None = None
|
|
125
|
-
self._driver = None # Neo4j driver
|
|
126
|
-
self._pending_writes: list[tuple[str, dict[str, Any]]] = []
|
|
127
|
-
self._write_lock = asyncio.Lock()
|
|
128
|
-
self._concept_cache: set[str] | None = None # names of known concepts
|
|
129
|
-
|
|
130
|
-
# ---------------------------------------------------------------------
|
|
131
|
-
# Connections
|
|
132
|
-
# ---------------------------------------------------------------------
|
|
133
|
-
def _ensure_embedding_model(self) -> SentenceTransformer:
|
|
134
|
-
if self._embedding_model is None:
|
|
135
|
-
logger.debug("Loading embedding model 'all-MiniLM-L6-v2'")
|
|
136
|
-
with tracer.start_as_current_span("memory.load_embedding_model") as span:
|
|
137
|
-
try:
|
|
138
|
-
self._embedding_model = SentenceTransformer("all-MiniLM-L6-v2")
|
|
139
|
-
span.set_attribute("model", "all-MiniLM-L6-v2")
|
|
140
|
-
except Exception as e:
|
|
141
|
-
span.record_exception(e)
|
|
142
|
-
raise
|
|
143
|
-
return self._embedding_model
|
|
144
|
-
|
|
145
|
-
def _ensure_adapter(self) -> VectorAdapter:
|
|
146
|
-
if self._adapter is not None:
|
|
147
|
-
return self._adapter
|
|
148
|
-
|
|
149
|
-
backend = self.cfg.vector_backend
|
|
150
|
-
|
|
151
|
-
if backend == "chroma":
|
|
152
|
-
self._adapter = ChromaAdapter(
|
|
153
|
-
collection=self.cfg.chroma_collection,
|
|
154
|
-
host=self.cfg.chroma_host,
|
|
155
|
-
port=self.cfg.chroma_port,
|
|
156
|
-
path=self.cfg.chroma_path,
|
|
157
|
-
)
|
|
158
|
-
elif backend == "pinecone":
|
|
159
|
-
self._adapter = PineconeAdapter(
|
|
160
|
-
api_key=self.cfg.pinecone_api_key,
|
|
161
|
-
environment=self.cfg.pinecone_env,
|
|
162
|
-
index=self.cfg.pinecone_index,
|
|
163
|
-
)
|
|
164
|
-
elif backend == "azure":
|
|
165
|
-
self._adapter = AzureSearchAdapter(
|
|
166
|
-
endpoint=self.cfg.azure_search_endpoint,
|
|
167
|
-
key=self.cfg.azure_search_key,
|
|
168
|
-
index_name=self.cfg.azure_search_index_name,
|
|
169
|
-
)
|
|
170
|
-
elif backend == "faiss":
|
|
171
|
-
self._adapter = FAISSAdapter(index_path="./faiss.index")
|
|
172
|
-
else:
|
|
173
|
-
raise ValueError(f"Unsupported vector backend: {backend}")
|
|
174
|
-
|
|
175
|
-
return self._adapter
|
|
176
|
-
|
|
177
|
-
def _ensure_graph_driver(self):
|
|
178
|
-
if self._driver is None:
|
|
179
|
-
self._driver = AsyncGraphDatabase.driver(
|
|
180
|
-
self.cfg.cypher_uri,
|
|
181
|
-
auth=(self.cfg.cypher_username, self.cfg.cypher_password),
|
|
182
|
-
encrypted=False,
|
|
183
|
-
)
|
|
184
|
-
return self._driver
|
|
185
|
-
|
|
186
|
-
# ---------------------------------------------------------------------
|
|
187
|
-
# Public API
|
|
188
|
-
# ---------------------------------------------------------------------
|
|
189
|
-
async def add_entry(
|
|
190
|
-
self,
|
|
191
|
-
content: str,
|
|
192
|
-
concepts: set[str],
|
|
193
|
-
metadata: dict[str, Any] | None = None,
|
|
194
|
-
) -> str:
|
|
195
|
-
"""Store a chunk in both vector store and graph DB and return its id."""
|
|
196
|
-
with tracer.start_as_current_span("memory.add_entry") as span:
|
|
197
|
-
span.set_attribute("entry_id", str(uuid.uuid4()))
|
|
198
|
-
|
|
199
|
-
# Embed
|
|
200
|
-
embedding = self._ensure_embedding_model().encode(content).tolist()
|
|
201
|
-
span.set_attribute("embedding_length", len(embedding))
|
|
202
|
-
|
|
203
|
-
# Vector store write
|
|
204
|
-
adapter = self._ensure_adapter()
|
|
205
|
-
span.set_attribute("vector_backend", self.cfg.vector_backend)
|
|
206
|
-
|
|
207
|
-
start_t = time.perf_counter()
|
|
208
|
-
try:
|
|
209
|
-
adapter.add(
|
|
210
|
-
id=span.get_attribute("entry_id"),
|
|
211
|
-
content=content,
|
|
212
|
-
embedding=embedding,
|
|
213
|
-
metadata=metadata,
|
|
214
|
-
)
|
|
215
|
-
except Exception as e:
|
|
216
|
-
span.record_exception(e)
|
|
217
|
-
raise
|
|
218
|
-
finally:
|
|
219
|
-
elapsed = (time.perf_counter() - start_t) * 1000 # ms
|
|
220
|
-
self._metrics.record(
|
|
221
|
-
"memory_add_latency_ms",
|
|
222
|
-
elapsed,
|
|
223
|
-
{"backend": self.cfg.vector_backend},
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
# Schedule graph writes (batched)
|
|
227
|
-
async with self._write_lock:
|
|
228
|
-
self._pending_writes.append((span.get_attribute("entry_id"), {"concepts": concepts}))
|
|
229
|
-
if self.cfg.save_interval and len(self._pending_writes) >= self.cfg.save_interval:
|
|
230
|
-
await self._flush_pending_graph_writes()
|
|
231
|
-
return span.get_attribute("entry_id")
|
|
232
|
-
|
|
233
|
-
async def search(
|
|
234
|
-
self, query_text: str, threshold: float, k: int
|
|
235
|
-
) -> list[dict[str, Any]]:
|
|
236
|
-
"""Vector similarity search followed by graph enrichment."""
|
|
237
|
-
with tracer.start_as_current_span("memory.search") as span:
|
|
238
|
-
span.set_attribute("vector_backend", self.cfg.vector_backend)
|
|
239
|
-
embedding = (
|
|
240
|
-
self._ensure_embedding_model().encode(query_text).tolist()
|
|
241
|
-
)
|
|
242
|
-
span.set_attribute("embedding_length", len(embedding))
|
|
243
|
-
adapter = self._ensure_adapter()
|
|
244
|
-
backend = self.cfg.vector_backend
|
|
245
|
-
results: list[dict[str, Any]] = []
|
|
246
|
-
|
|
247
|
-
search_start = time.perf_counter()
|
|
248
|
-
vector_hits = adapter.query(embedding=embedding, k=k)
|
|
249
|
-
search_elapsed = (time.perf_counter() - search_start) * 1000
|
|
250
|
-
self._metrics.record(
|
|
251
|
-
"memory_search_hits", len(vector_hits), {"backend": backend}
|
|
252
|
-
)
|
|
253
|
-
for hit in vector_hits:
|
|
254
|
-
if hit.score < threshold:
|
|
255
|
-
continue
|
|
256
|
-
results.append(
|
|
257
|
-
{
|
|
258
|
-
"id": hit.id,
|
|
259
|
-
"content": hit.content,
|
|
260
|
-
"metadata": hit.metadata,
|
|
261
|
-
"score": hit.score,
|
|
262
|
-
}
|
|
263
|
-
)
|
|
264
|
-
|
|
265
|
-
span.set_attribute("results_count", len(results))
|
|
266
|
-
self._metrics.record(
|
|
267
|
-
"memory_search_latency_ms", search_elapsed, {"backend": backend}
|
|
268
|
-
)
|
|
269
|
-
return results
|
|
270
|
-
|
|
271
|
-
# ------------------------------------------------------------------
|
|
272
|
-
# Graph persistence helpers
|
|
273
|
-
# ------------------------------------------------------------------
|
|
274
|
-
async def _flush_pending_graph_writes(self):
|
|
275
|
-
"""Commit queued node/edge creations to the Cypher store."""
|
|
276
|
-
if not self._pending_writes:
|
|
277
|
-
return
|
|
278
|
-
driver = self._ensure_graph_driver()
|
|
279
|
-
async with driver.session() as session:
|
|
280
|
-
tx_commands: list[str] = []
|
|
281
|
-
params: dict[str, Any] = {}
|
|
282
|
-
# Build Cypher in one transaction
|
|
283
|
-
for idx, (entry_id, extra) in enumerate(self._pending_writes):
|
|
284
|
-
concept_param = f"concepts_{idx}"
|
|
285
|
-
tx_commands.append(
|
|
286
|
-
f"MERGE (e:Memory {{id: '{entry_id}'}}) "
|
|
287
|
-
f"SET e.created = datetime() "
|
|
288
|
-
)
|
|
289
|
-
if extra.get("concepts"):
|
|
290
|
-
tx_commands.append(
|
|
291
|
-
f"WITH e UNWIND ${concept_param} AS c "
|
|
292
|
-
"MERGE (co:Concept {name: c}) "
|
|
293
|
-
"MERGE (e)-[:MENTIONS]->(co)"
|
|
294
|
-
)
|
|
295
|
-
params[concept_param] = list(extra["concepts"])
|
|
296
|
-
cypher = "\n".join(tx_commands)
|
|
297
|
-
await session.run(cypher, params)
|
|
298
|
-
# Export graph image if requested
|
|
299
|
-
if self.cfg.export_graph_image:
|
|
300
|
-
await self._export_graph_image(session)
|
|
301
|
-
self._pending_writes.clear()
|
|
302
|
-
|
|
303
|
-
async def _export_graph_image(self, session):
|
|
304
|
-
"""Generate and save a PNG of the concept graph."""
|
|
305
|
-
try:
|
|
306
|
-
import matplotlib
|
|
307
|
-
matplotlib.use("Agg")
|
|
308
|
-
import matplotlib.pyplot as plt
|
|
309
|
-
import networkx as nx
|
|
310
|
-
|
|
311
|
-
records = await session.run(
|
|
312
|
-
"MATCH (c1:Concept)<-[:MENTIONS]-(:Memory)-[:MENTIONS]->(c2:Concept) "
|
|
313
|
-
"RETURN DISTINCT c1.name AS source, c2.name AS target"
|
|
314
|
-
)
|
|
315
|
-
edges = [(r["source"], r["target"]) for r in await records.values("source", "target")]
|
|
316
|
-
if not edges:
|
|
317
|
-
return
|
|
318
|
-
|
|
319
|
-
G = nx.Graph()
|
|
320
|
-
G.add_edges_from(edges)
|
|
321
|
-
|
|
322
|
-
pos = nx.spring_layout(G, k=0.4)
|
|
323
|
-
plt.figure(figsize=(12, 9), dpi=100)
|
|
324
|
-
nx.draw_networkx_nodes(G, pos, node_color="#8fa8d6", node_size=500, edgecolors="white")
|
|
325
|
-
nx.draw_networkx_edges(G, pos, alpha=0.5, width=1.5)
|
|
326
|
-
nx.draw_networkx_labels(G, pos, font_size=8)
|
|
327
|
-
plt.axis("off")
|
|
328
|
-
|
|
329
|
-
img_dir = Path(self.cfg.graph_image_dir)
|
|
330
|
-
img_dir.mkdir(parents=True, exist_ok=True)
|
|
331
|
-
filename = img_dir / f"concept_graph_{uuid.uuid4().hex[:8]}.png"
|
|
332
|
-
plt.savefig(filename, bbox_inches="tight", facecolor="white")
|
|
333
|
-
plt.close()
|
|
334
|
-
logger.info("Concept graph image exported to %s", filename)
|
|
335
|
-
except Exception as e:
|
|
336
|
-
logger.warning("Failed to export concept graph image: %s", e)
|
|
337
|
-
|
|
338
|
-
async def close(self):
|
|
339
|
-
if self._pending_writes:
|
|
340
|
-
await self._flush_pending_graph_writes()
|
|
341
|
-
if self._driver:
|
|
342
|
-
await self._driver.close()
|
|
343
|
-
if self._adapter and hasattr(self._adapter, "close"):
|
|
344
|
-
self._adapter.close()
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
# ---------------------------------------------------------------------------
|
|
348
|
-
# Module
|
|
349
|
-
# ---------------------------------------------------------------------------
|
|
350
|
-
@flock_component(config_class=EnterpriseMemoryModuleConfig)
|
|
351
|
-
class EnterpriseMemoryModule(FlockModule):
|
|
352
|
-
"""Enterprise-ready memory module using real datastores."""
|
|
353
|
-
|
|
354
|
-
name: str = "enterprise_memory"
|
|
355
|
-
config: EnterpriseMemoryModuleConfig = Field(default_factory=EnterpriseMemoryModuleConfig)
|
|
356
|
-
|
|
357
|
-
_store: EnterpriseMemoryStore | None = None
|
|
358
|
-
_container: Any | None = None # DI container if supplied
|
|
359
|
-
_metrics_module: MetricsModule | None = None
|
|
360
|
-
|
|
361
|
-
# ----------------------------------------------------------
|
|
362
|
-
# DI-enabled constructor
|
|
363
|
-
# ----------------------------------------------------------
|
|
364
|
-
def __init__(
|
|
365
|
-
self,
|
|
366
|
-
name: str = "enterprise_memory",
|
|
367
|
-
config: EnterpriseMemoryModuleConfig | None = None,
|
|
368
|
-
*,
|
|
369
|
-
container: object | None = None,
|
|
370
|
-
**kwargs,
|
|
371
|
-
):
|
|
372
|
-
"""Create a new EnterpriseMemoryModule instance.
|
|
373
|
-
|
|
374
|
-
Parameters
|
|
375
|
-
----------
|
|
376
|
-
container : ServiceProvider | None
|
|
377
|
-
Optional DI container used to resolve shared services. When
|
|
378
|
-
provided, the module will attempt to resolve
|
|
379
|
-
:class:`flock.modules.performance.metrics_module.MetricsModule` from
|
|
380
|
-
it. Falling back to the global singleton when not available keeps
|
|
381
|
-
backward-compatibility.
|
|
382
|
-
"""
|
|
383
|
-
from wd.di.container import (
|
|
384
|
-
ServiceProvider, # Local import to avoid hard dependency if wd.di is absent
|
|
385
|
-
)
|
|
386
|
-
|
|
387
|
-
if config is None:
|
|
388
|
-
config = EnterpriseMemoryModuleConfig()
|
|
389
|
-
|
|
390
|
-
super().__init__(name=name, config=config, **kwargs)
|
|
391
|
-
|
|
392
|
-
self._container = container if isinstance(container, ServiceProvider) else None
|
|
393
|
-
|
|
394
|
-
# Attempt to resolve MetricsModule via DI, then via FlockModule registry
|
|
395
|
-
resolved_metrics: MetricsModule | None = None
|
|
396
|
-
if self._container is not None:
|
|
397
|
-
try:
|
|
398
|
-
resolved_metrics = self._container.get_service(MetricsModule)
|
|
399
|
-
except Exception:
|
|
400
|
-
resolved_metrics = None
|
|
401
|
-
|
|
402
|
-
if resolved_metrics is None:
|
|
403
|
-
resolved_metrics = MetricsModule._INSTANCE
|
|
404
|
-
|
|
405
|
-
self._metrics_module = resolved_metrics
|
|
406
|
-
|
|
407
|
-
# ----------------------------------------------------------
|
|
408
|
-
# Life-cycle hooks
|
|
409
|
-
# ----------------------------------------------------------
|
|
410
|
-
async def on_initialize(
|
|
411
|
-
self,
|
|
412
|
-
agent: FlockAgent,
|
|
413
|
-
inputs: dict[str, Any],
|
|
414
|
-
context: FlockContext | None = None,
|
|
415
|
-
) -> None:
|
|
416
|
-
self._store = EnterpriseMemoryStore(self.config, self._metrics_module)
|
|
417
|
-
logger.info("EnterpriseMemoryModule initialised", agent=agent.name)
|
|
418
|
-
|
|
419
|
-
async def on_pre_evaluate(
|
|
420
|
-
self,
|
|
421
|
-
agent: FlockAgent,
|
|
422
|
-
inputs: dict[str, Any],
|
|
423
|
-
context: FlockContext | None = None,
|
|
424
|
-
) -> dict[str, Any]:
|
|
425
|
-
if not self._store:
|
|
426
|
-
return inputs
|
|
427
|
-
try:
|
|
428
|
-
query_str = json.dumps(inputs)
|
|
429
|
-
matches = await self._store.search(
|
|
430
|
-
query_str,
|
|
431
|
-
threshold=self.config.similarity_threshold,
|
|
432
|
-
k=self.config.max_results,
|
|
433
|
-
)
|
|
434
|
-
if matches:
|
|
435
|
-
inputs = {**inputs, "context": matches}
|
|
436
|
-
# Advertise new input key to DSPy signature if needed
|
|
437
|
-
if isinstance(agent.input, str) and "context:" not in agent.input:
|
|
438
|
-
agent.input += ", context: list | retrieved memories"
|
|
439
|
-
except Exception as e:
|
|
440
|
-
logger.warning("Enterprise memory retrieval failed: %s", e, agent=agent.name)
|
|
441
|
-
return inputs
|
|
442
|
-
|
|
443
|
-
async def on_post_evaluate(
|
|
444
|
-
self,
|
|
445
|
-
agent: FlockAgent,
|
|
446
|
-
inputs: dict[str, Any],
|
|
447
|
-
context: FlockContext | None = None,
|
|
448
|
-
result: dict[str, Any] | None = None,
|
|
449
|
-
) -> dict[str, Any] | None:
|
|
450
|
-
if not self._store:
|
|
451
|
-
return result
|
|
452
|
-
try:
|
|
453
|
-
full_text = json.dumps(inputs) + (json.dumps(result) if result else "")
|
|
454
|
-
concepts = await self._extract_concepts(agent, full_text)
|
|
455
|
-
if self._store:
|
|
456
|
-
concepts = await self._store._deduplicate_concepts(concepts)
|
|
457
|
-
await self._store.add_entry(full_text, concepts)
|
|
458
|
-
except Exception as e:
|
|
459
|
-
logger.warning("Enterprise memory store failed: %s", e, agent=agent.name)
|
|
460
|
-
return result
|
|
461
|
-
|
|
462
|
-
async def on_terminate(
|
|
463
|
-
self,
|
|
464
|
-
agent: FlockAgent,
|
|
465
|
-
inputs: dict[str, Any],
|
|
466
|
-
result: dict[str, Any],
|
|
467
|
-
context: FlockContext | None = None,
|
|
468
|
-
) -> None:
|
|
469
|
-
if self._store:
|
|
470
|
-
await self._store.close()
|
|
471
|
-
|
|
472
|
-
# ----------------------------------------------------------
|
|
473
|
-
# Helpers (mostly copied from original module but simplified)
|
|
474
|
-
# ----------------------------------------------------------
|
|
475
|
-
async def _extract_concepts(self, agent: FlockAgent, text: str) -> set[str]:
|
|
476
|
-
"""Use the LLM to extract concept tokens."""
|
|
477
|
-
concept_signature = agent.create_dspy_signature_class(
|
|
478
|
-
f"{agent.name}_concept_extractor_enterprise",
|
|
479
|
-
"Extract key concepts from text",
|
|
480
|
-
"text: str | Input text -> concepts: list[str] | key concepts lower case",
|
|
481
|
-
)
|
|
482
|
-
agent._configure_language_model(agent.model, True, 0.0, 8192)
|
|
483
|
-
predictor = agent._select_task(concept_signature, "Completion")
|
|
484
|
-
res = predictor(text=text)
|
|
485
|
-
return set(getattr(res, "concepts", []))
|
|
486
|
-
|
|
487
|
-
# --------------------------------------------------------------
|
|
488
|
-
# Concept helpers
|
|
489
|
-
# --------------------------------------------------------------
|
|
490
|
-
async def _ensure_concept_cache(self):
|
|
491
|
-
if self._concept_cache is not None:
|
|
492
|
-
return
|
|
493
|
-
driver = self._ensure_graph_driver()
|
|
494
|
-
async with driver.session() as session:
|
|
495
|
-
records = await session.run("MATCH (c:Concept) RETURN c.name AS name")
|
|
496
|
-
self._concept_cache = {r["name"] for r in await records.values("name")}
|
|
497
|
-
|
|
498
|
-
async def _deduplicate_concepts(self, new_concepts: set[str]) -> set[str]:
|
|
499
|
-
"""Return a set of concept names that merges with existing ones to avoid duplicates.
|
|
500
|
-
|
|
501
|
-
Strategy: case-insensitive equality first, then fuzzy match via difflib with cutoff 0.85.
|
|
502
|
-
"""
|
|
503
|
-
await self._ensure_concept_cache()
|
|
504
|
-
assert self._concept_cache is not None
|
|
505
|
-
|
|
506
|
-
from difflib import get_close_matches
|
|
507
|
-
|
|
508
|
-
unified: set[str] = set()
|
|
509
|
-
for concept in new_concepts:
|
|
510
|
-
# Exact (case-insensitive) match
|
|
511
|
-
lower = concept.lower()
|
|
512
|
-
exact = next((c for c in self._concept_cache if c.lower() == lower), None)
|
|
513
|
-
if exact:
|
|
514
|
-
unified.add(exact)
|
|
515
|
-
continue
|
|
516
|
-
|
|
517
|
-
# Fuzzy match (>=0.85 similarity)
|
|
518
|
-
close = get_close_matches(concept, list(self._concept_cache), n=1, cutoff=0.85)
|
|
519
|
-
if close:
|
|
520
|
-
unified.add(close[0])
|
|
521
|
-
continue
|
|
522
|
-
|
|
523
|
-
# No match – treat as new
|
|
524
|
-
unified.add(concept)
|
|
525
|
-
self._concept_cache.add(concept)
|
|
526
|
-
return unified
|
flock/modules/mem0/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# Package for modules
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
# from mem0.client.main import MemoryClient
|
|
4
|
-
# from mem0.memory.main import Memory
|
|
5
|
-
from mem0 import Memory, MemoryClient
|
|
6
|
-
from pydantic import Field
|
|
7
|
-
|
|
8
|
-
from flock.core.context.context import FlockContext
|
|
9
|
-
from flock.core.flock_agent import FlockAgent
|
|
10
|
-
from flock.core.flock_module import FlockModule, FlockModuleConfig
|
|
11
|
-
from flock.core.flock_registry import flock_component
|
|
12
|
-
from flock.core.logging.logging import get_logger
|
|
13
|
-
|
|
14
|
-
logger = get_logger("module.mem0")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
config = {
|
|
18
|
-
"vector_store": {
|
|
19
|
-
"provider": "chroma",
|
|
20
|
-
"config": {
|
|
21
|
-
"collection_name": "flock_memory",
|
|
22
|
-
"path": ".flock/memory",
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class Mem0ModuleConfig(FlockModuleConfig):
|
|
29
|
-
top_k: int = Field(default=10, description="Number of memories to retrieve")
|
|
30
|
-
user_id: str = Field(default="flock", description="User ID the memories will be associated with")
|
|
31
|
-
agent_id: str = Field(default="flock", description="Agent ID the memories will be associated with")
|
|
32
|
-
memory_input_key: str | None = Field(default=None, description="Input key to use for memory, if none the description of the agent will be used")
|
|
33
|
-
api_key: str | None = Field(default=None, description="API key for mem0 Platform")
|
|
34
|
-
config: dict[str, Any] = Field(default=config, description="Configuration for mem0")
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@flock_component(config_class=Mem0ModuleConfig)
|
|
38
|
-
class Mem0Module(FlockModule):
|
|
39
|
-
|
|
40
|
-
name: str = "mem0"
|
|
41
|
-
config: Mem0ModuleConfig = Mem0ModuleConfig()
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def __init__(self, name, config: Mem0ModuleConfig) -> None:
|
|
45
|
-
global memory
|
|
46
|
-
"""Initialize Mem0 module."""
|
|
47
|
-
super().__init__(name=name, config=config)
|
|
48
|
-
logger.debug("Initializing Mem0 module")
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def dict_to_str_repr(self,d: dict) -> str:
|
|
54
|
-
return repr(d)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
async def on_post_evaluate(
|
|
58
|
-
self,
|
|
59
|
-
agent: FlockAgent,
|
|
60
|
-
inputs: dict[str, Any],
|
|
61
|
-
context: FlockContext | None = None,
|
|
62
|
-
result: dict[str, Any] | None = None,
|
|
63
|
-
) -> dict[str, Any]:
|
|
64
|
-
if self.config.api_key:
|
|
65
|
-
memory = MemoryClient(api_key=self.config.api_key)
|
|
66
|
-
else:
|
|
67
|
-
memory = Memory.from_config(config_dict=self.config.config)
|
|
68
|
-
|
|
69
|
-
agent_id = self.config.agent_id if self.config.agent_id else agent.name
|
|
70
|
-
|
|
71
|
-
# get the result without the inputs
|
|
72
|
-
filtered_result = {k: v for k, v in result.items() if k not in inputs}
|
|
73
|
-
# get the inputs without memory
|
|
74
|
-
filtered_inputs = {k: v for k, v in inputs.items() if k not in [self.config.memory_input_key]}
|
|
75
|
-
|
|
76
|
-
# add memories about the user inputs
|
|
77
|
-
added_user_memory = memory.add(self.dict_to_str_repr(filtered_inputs), user_id=self.config.user_id)
|
|
78
|
-
logger.info(f"Added caller memory: {added_user_memory}")
|
|
79
|
-
|
|
80
|
-
# add memories about the agent result
|
|
81
|
-
added_agent_memory = memory.add(self.dict_to_str_repr(filtered_result), agent_id=agent_id)
|
|
82
|
-
logger.info(f"Added agent memory: {added_agent_memory}")
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return result
|
|
86
|
-
|
|
87
|
-
async def on_pre_evaluate(
|
|
88
|
-
self,
|
|
89
|
-
agent: FlockAgent,
|
|
90
|
-
inputs: dict[str, Any],
|
|
91
|
-
context: FlockContext | None = None,
|
|
92
|
-
) -> dict[str, Any]:
|
|
93
|
-
if self.config.api_key:
|
|
94
|
-
memory = MemoryClient(api_key=self.config.api_key)
|
|
95
|
-
else:
|
|
96
|
-
memory = Memory.from_config(config_dict=self.config.config)
|
|
97
|
-
|
|
98
|
-
message = self.dict_to_str_repr(inputs)
|
|
99
|
-
agent_id = self.config.agent_id if self.config.agent_id else agent.name
|
|
100
|
-
|
|
101
|
-
relevant_agent_memories = memory.search(query=message, agent_id=agent_id, limit=self.config.top_k)
|
|
102
|
-
logger.info(f"Relevant agent memories: {relevant_agent_memories}")
|
|
103
|
-
|
|
104
|
-
relevant_user_memories = memory.search(query=message, user_id=self.config.user_id, limit=self.config.top_k)
|
|
105
|
-
logger.info(f"Relevant user memories: {relevant_user_memories}")
|
|
106
|
-
|
|
107
|
-
if relevant_agent_memories or relevant_user_memories:
|
|
108
|
-
memories_str = ''
|
|
109
|
-
if "results" in relevant_agent_memories:
|
|
110
|
-
memories_str = "\n".join(f"- {entry['memory']}" for entry in relevant_agent_memories["results"])
|
|
111
|
-
else:
|
|
112
|
-
memories_str = "\n".join(f"- {entry}" for entry in relevant_agent_memories)
|
|
113
|
-
|
|
114
|
-
if "results" in relevant_user_memories:
|
|
115
|
-
memories_str = memories_str + "\n" + "\n".join(f"- {entry['memory']}" for entry in relevant_user_memories["results"])
|
|
116
|
-
else:
|
|
117
|
-
memories_str = memories_str + "\n" + "\n".join(f"- {entry}" for entry in relevant_user_memories)
|
|
118
|
-
|
|
119
|
-
if memories_str:
|
|
120
|
-
if self.config.memory_input_key:
|
|
121
|
-
inputs[self.config.memory_input_key] = memories_str
|
|
122
|
-
else:
|
|
123
|
-
agent.description = agent.description + "\n\n Memories:" + memories_str
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return inputs
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# Package for modules
|