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
|
@@ -14,13 +14,12 @@ import logging
|
|
|
14
14
|
import sys
|
|
15
15
|
from typing import Literal
|
|
16
16
|
|
|
17
|
-
from opentelemetry import trace
|
|
18
|
-
|
|
19
17
|
# Always import Temporal workflow (since it's part of the project)
|
|
20
|
-
from temporalio import workflow
|
|
18
|
+
# from temporalio import workflow
|
|
19
|
+
# with workflow.unsafe.imports_passed_through():
|
|
20
|
+
from loguru import logger as loguru_logger
|
|
21
|
+
from opentelemetry import trace
|
|
21
22
|
|
|
22
|
-
with workflow.unsafe.imports_passed_through():
|
|
23
|
-
from loguru import logger as loguru_logger
|
|
24
23
|
|
|
25
24
|
# ENABLED_FLOCK_LOGGER_LEVELS constant removed
|
|
26
25
|
|
|
@@ -42,13 +41,14 @@ def in_workflow_context() -> bool:
|
|
|
42
41
|
It does this by attempting to call workflow.info() and returning True
|
|
43
42
|
if successful. Otherwise, it returns False.
|
|
44
43
|
"""
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
return False
|
|
45
|
+
# try:
|
|
46
|
+
# workflow.logger.debug("Checking if in workflow context...")
|
|
47
|
+
# # loguru_logger.debug("Checking if in workflow context...")
|
|
48
|
+
# # This call will succeed only if we're in a workflow context.
|
|
49
|
+
# return bool(hasattr(workflow.info(), "is_replaying"))
|
|
50
|
+
# except Exception:
|
|
51
|
+
# return False
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
def get_current_trace_id() -> str:
|
|
@@ -108,7 +108,7 @@ COLOR_MAP = {
|
|
|
108
108
|
|
|
109
109
|
LOGGERS = [
|
|
110
110
|
"flock", # Core Flock orchestration
|
|
111
|
-
"flock.api",
|
|
111
|
+
"flock.api", # Flock API specific logs
|
|
112
112
|
"agent", # General agent operations
|
|
113
113
|
"context", # Context management
|
|
114
114
|
"registry", # Unified registry operations (new)
|
|
@@ -154,6 +154,7 @@ def color_for_category(category: str) -> str:
|
|
|
154
154
|
if category in COLOR_MAP:
|
|
155
155
|
return COLOR_MAP[category]
|
|
156
156
|
parts = category.split(".")
|
|
157
|
+
# Try progressively shorter parent categories
|
|
157
158
|
for i in range(len(parts) - 1, 0, -1):
|
|
158
159
|
parent_category = ".".join(parts[:i])
|
|
159
160
|
if parent_category in COLOR_MAP:
|
|
@@ -176,9 +177,7 @@ def custom_format(record):
|
|
|
176
177
|
# MAX_LENGTH = 500 # Example value
|
|
177
178
|
if len(message) > MAX_LENGTH:
|
|
178
179
|
truncated_chars = len(message) - MAX_LENGTH
|
|
179
|
-
message = (
|
|
180
|
-
message[:MAX_LENGTH] + f"<yellow>...+({truncated_chars} chars)</yellow>"
|
|
181
|
-
)
|
|
180
|
+
message = message[:MAX_LENGTH] + f"<yellow>...+({truncated_chars} chars)</yellow>"
|
|
182
181
|
|
|
183
182
|
# Determine if category needs bolding (can refine this logic)
|
|
184
183
|
needs_bold = category in BOLD_CATEGORIES
|
|
@@ -246,7 +245,6 @@ class PrintAndFlushSink:
|
|
|
246
245
|
|
|
247
246
|
Already flushed on every write call.
|
|
248
247
|
"""
|
|
249
|
-
pass
|
|
250
248
|
|
|
251
249
|
|
|
252
250
|
# Configure Loguru for non-workflow (local/worker) contexts.
|
|
@@ -263,7 +261,9 @@ logging.basicConfig(level=LOG_LEVELS["ERROR"]) # Default to ERROR level for fal
|
|
|
263
261
|
# loguru_logger.add("logs/flock.log", rotation="100 MB", retention="30 days", level="DEBUG")
|
|
264
262
|
|
|
265
263
|
|
|
266
|
-
def get_default_severity(
|
|
264
|
+
def get_default_severity(
|
|
265
|
+
level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NO_LOGS", "SUCCESS"] | int,
|
|
266
|
+
) -> int:
|
|
267
267
|
"""Get the default severity for a given level."""
|
|
268
268
|
if isinstance(level, str):
|
|
269
269
|
level_str = level.upper()
|
|
@@ -271,9 +271,17 @@ def get_default_severity(level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CR
|
|
|
271
271
|
return level
|
|
272
272
|
|
|
273
273
|
|
|
274
|
-
def configure_logging(
|
|
275
|
-
|
|
276
|
-
|
|
274
|
+
def configure_logging(
|
|
275
|
+
flock_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NO_LOGS", "SUCCESS"]
|
|
276
|
+
| int,
|
|
277
|
+
external_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NO_LOGS", "SUCCESS"]
|
|
278
|
+
| int,
|
|
279
|
+
specific_levels: dict[
|
|
280
|
+
str,
|
|
281
|
+
Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NO_LOGS", "SUCCESS"] | int,
|
|
282
|
+
]
|
|
283
|
+
| None = None,
|
|
284
|
+
) -> None:
|
|
277
285
|
"""Configure both external and internal Flock logging systems.
|
|
278
286
|
|
|
279
287
|
Args:
|
|
@@ -282,19 +290,21 @@ def configure_logging(flock_level: Literal["DEBUG", "INFO", "WARNING", "ERROR",
|
|
|
282
290
|
specific_levels (dict[str, str | int] | None, optional): A dictionary mapping
|
|
283
291
|
logger names to their specific logging levels. Defaults to None.
|
|
284
292
|
"""
|
|
285
|
-
|
|
293
|
+
global _DEFAULT_FLOCK_SEVERITY, _SPECIFIC_SEVERITIES
|
|
286
294
|
|
|
295
|
+
# Get default severity
|
|
287
296
|
external_severity = get_default_severity(external_level)
|
|
288
297
|
logging.basicConfig(level=external_severity)
|
|
289
298
|
|
|
290
|
-
|
|
291
299
|
flock_severity = get_default_severity(flock_level)
|
|
300
|
+
_DEFAULT_FLOCK_SEVERITY = flock_severity # Store for future loggers
|
|
292
301
|
|
|
293
302
|
specific_severities = {}
|
|
294
303
|
if specific_levels:
|
|
295
304
|
for name, logger_level in specific_levels.items():
|
|
296
305
|
severity = get_default_severity(logger_level)
|
|
297
306
|
specific_severities[name] = severity
|
|
307
|
+
_SPECIFIC_SEVERITIES[name] = severity # Store for future loggers
|
|
298
308
|
|
|
299
309
|
# Apply to all cached loggers
|
|
300
310
|
for logger_name, log_instance in _LOGGER_CACHE.items():
|
|
@@ -305,28 +315,26 @@ def configure_logging(flock_level: Literal["DEBUG", "INFO", "WARNING", "ERROR",
|
|
|
305
315
|
log_instance.min_level_severity = target_severity
|
|
306
316
|
|
|
307
317
|
|
|
308
|
-
|
|
309
|
-
|
|
310
318
|
# Define a dummy logger that does nothing
|
|
311
319
|
class DummyLogger:
|
|
312
320
|
"""A dummy logger that does nothing when called."""
|
|
313
321
|
|
|
314
|
-
def debug(self, *args, **kwargs):
|
|
322
|
+
def debug(self, *args, **kwargs):
|
|
315
323
|
pass
|
|
316
324
|
|
|
317
|
-
def info(self, *args, **kwargs):
|
|
325
|
+
def info(self, *args, **kwargs):
|
|
318
326
|
pass
|
|
319
327
|
|
|
320
|
-
def warning(self, *args, **kwargs):
|
|
328
|
+
def warning(self, *args, **kwargs):
|
|
321
329
|
pass
|
|
322
330
|
|
|
323
|
-
def error(self, *args, **kwargs):
|
|
331
|
+
def error(self, *args, **kwargs):
|
|
324
332
|
pass
|
|
325
333
|
|
|
326
|
-
def exception(self, *args, **kwargs):
|
|
334
|
+
def exception(self, *args, **kwargs):
|
|
327
335
|
pass
|
|
328
336
|
|
|
329
|
-
def success(self, *args, **kwargs):
|
|
337
|
+
def success(self, *args, **kwargs):
|
|
330
338
|
pass
|
|
331
339
|
|
|
332
340
|
|
|
@@ -356,9 +364,9 @@ class FlockLogger:
|
|
|
356
364
|
self.min_level_severity = initial_min_level_severity
|
|
357
365
|
|
|
358
366
|
def _get_logger(self):
|
|
359
|
-
if in_workflow_context():
|
|
360
|
-
|
|
361
|
-
|
|
367
|
+
# if in_workflow_context():
|
|
368
|
+
# # Use Temporal's workflow.logger inside a workflow context.
|
|
369
|
+
# return workflow.logger
|
|
362
370
|
# Bind our logger with category and trace_id
|
|
363
371
|
return loguru_logger.bind(
|
|
364
372
|
name=self.name,
|
|
@@ -370,9 +378,7 @@ class FlockLogger:
|
|
|
370
378
|
"""Truncate a message if it exceeds max_length and add truncation indicator."""
|
|
371
379
|
if len(message) > max_length:
|
|
372
380
|
truncated_chars = len(message) - max_length
|
|
373
|
-
return (
|
|
374
|
-
message[:max_length] + f"...<yellow>+({truncated_chars} chars)</yellow>"
|
|
375
|
-
)
|
|
381
|
+
return message[:max_length] + f"...<yellow>+({truncated_chars} chars)</yellow>"
|
|
376
382
|
return message
|
|
377
383
|
|
|
378
384
|
def debug(
|
|
@@ -384,8 +390,10 @@ class FlockLogger:
|
|
|
384
390
|
**kwargs,
|
|
385
391
|
) -> None:
|
|
386
392
|
current_method_severity = LOG_LEVELS["DEBUG"]
|
|
387
|
-
if
|
|
388
|
-
|
|
393
|
+
if (
|
|
394
|
+
self.min_level_severity == LOG_LEVELS["NO_LOGS"]
|
|
395
|
+
or current_method_severity < self.min_level_severity
|
|
396
|
+
):
|
|
389
397
|
return
|
|
390
398
|
"""Debug a message.
|
|
391
399
|
|
|
@@ -406,8 +414,10 @@ class FlockLogger:
|
|
|
406
414
|
**kwargs,
|
|
407
415
|
) -> None:
|
|
408
416
|
current_method_severity = LOG_LEVELS["INFO"]
|
|
409
|
-
if
|
|
410
|
-
|
|
417
|
+
if (
|
|
418
|
+
self.min_level_severity == LOG_LEVELS["NO_LOGS"]
|
|
419
|
+
or current_method_severity < self.min_level_severity
|
|
420
|
+
):
|
|
411
421
|
return
|
|
412
422
|
"""Info a message.
|
|
413
423
|
|
|
@@ -428,8 +438,10 @@ class FlockLogger:
|
|
|
428
438
|
**kwargs,
|
|
429
439
|
) -> None:
|
|
430
440
|
current_method_severity = LOG_LEVELS["WARNING"]
|
|
431
|
-
if
|
|
432
|
-
|
|
441
|
+
if (
|
|
442
|
+
self.min_level_severity == LOG_LEVELS["NO_LOGS"]
|
|
443
|
+
or current_method_severity < self.min_level_severity
|
|
444
|
+
):
|
|
433
445
|
return
|
|
434
446
|
"""Warning a message.
|
|
435
447
|
|
|
@@ -450,8 +462,10 @@ class FlockLogger:
|
|
|
450
462
|
**kwargs,
|
|
451
463
|
) -> None:
|
|
452
464
|
current_method_severity = LOG_LEVELS["ERROR"]
|
|
453
|
-
if
|
|
454
|
-
|
|
465
|
+
if (
|
|
466
|
+
self.min_level_severity == LOG_LEVELS["NO_LOGS"]
|
|
467
|
+
or current_method_severity < self.min_level_severity
|
|
468
|
+
):
|
|
455
469
|
return
|
|
456
470
|
"""Error a message.
|
|
457
471
|
|
|
@@ -471,9 +485,11 @@ class FlockLogger:
|
|
|
471
485
|
max_length: int = MAX_LENGTH,
|
|
472
486
|
**kwargs,
|
|
473
487
|
) -> None:
|
|
474
|
-
current_method_severity = LOG_LEVELS["ERROR"]
|
|
475
|
-
if
|
|
476
|
-
|
|
488
|
+
current_method_severity = LOG_LEVELS["ERROR"] # Exception implies ERROR level
|
|
489
|
+
if (
|
|
490
|
+
self.min_level_severity == LOG_LEVELS["NO_LOGS"]
|
|
491
|
+
or current_method_severity < self.min_level_severity
|
|
492
|
+
):
|
|
477
493
|
return
|
|
478
494
|
"""Exception a message.
|
|
479
495
|
|
|
@@ -494,8 +510,10 @@ class FlockLogger:
|
|
|
494
510
|
**kwargs,
|
|
495
511
|
) -> None:
|
|
496
512
|
current_method_severity = LOG_LEVELS["SUCCESS"]
|
|
497
|
-
if
|
|
498
|
-
|
|
513
|
+
if (
|
|
514
|
+
self.min_level_severity == LOG_LEVELS["NO_LOGS"]
|
|
515
|
+
or current_method_severity < self.min_level_severity
|
|
516
|
+
):
|
|
499
517
|
return
|
|
500
518
|
"""Success a message.
|
|
501
519
|
|
|
@@ -509,21 +527,22 @@ class FlockLogger:
|
|
|
509
527
|
|
|
510
528
|
|
|
511
529
|
_LOGGER_CACHE: dict[str, FlockLogger] = {}
|
|
530
|
+
_DEFAULT_FLOCK_SEVERITY: int = LOG_LEVELS["ERROR"]
|
|
531
|
+
_SPECIFIC_SEVERITIES: dict[str, int] = {}
|
|
512
532
|
|
|
513
533
|
|
|
514
534
|
def get_logger(name: str = "flock") -> FlockLogger:
|
|
515
535
|
"""Return a cached FlockLogger instance for the given name.
|
|
516
536
|
|
|
517
|
-
If the logger doesn't exist, it is created
|
|
518
|
-
|
|
519
|
-
the `configure_logging()` function.
|
|
537
|
+
If the logger doesn't exist, it is created using the configured severity level
|
|
538
|
+
from configure_logging() (default: ERROR). Respects specific_levels if configured.
|
|
520
539
|
If a logger with the given name already exists in the cache, its 'min_level_severity'
|
|
521
540
|
state is NOT modified by this function; it's simply returned.
|
|
522
541
|
"""
|
|
523
542
|
if name not in _LOGGER_CACHE:
|
|
524
|
-
#
|
|
525
|
-
|
|
526
|
-
_LOGGER_CACHE[name] = FlockLogger(name,
|
|
543
|
+
# Check if there's a specific severity configured for this logger
|
|
544
|
+
severity = _SPECIFIC_SEVERITIES.get(name, _DEFAULT_FLOCK_SEVERITY)
|
|
545
|
+
_LOGGER_CACHE[name] = FlockLogger(name, severity)
|
|
527
546
|
# The min_level_severity state of existing or newly created loggers
|
|
528
547
|
# should be managed by the configure_logging() function.
|
|
529
548
|
return _LOGGER_CACHE[name]
|
|
@@ -543,15 +562,13 @@ def truncate_for_logging(obj, max_item_length=100, max_items=10):
|
|
|
543
562
|
"""Truncate large data structures for logging purposes."""
|
|
544
563
|
if isinstance(obj, str) and len(obj) > max_item_length:
|
|
545
564
|
return obj[:max_item_length] + f"... ({len(obj) - max_item_length} more chars)"
|
|
546
|
-
|
|
565
|
+
if isinstance(obj, dict):
|
|
547
566
|
if len(obj) > max_items:
|
|
548
567
|
return {
|
|
549
|
-
k: truncate_for_logging(v)
|
|
550
|
-
for i, (k, v) in enumerate(obj.items())
|
|
551
|
-
if i < max_items
|
|
568
|
+
k: truncate_for_logging(v) for i, (k, v) in enumerate(obj.items()) if i < max_items
|
|
552
569
|
}
|
|
553
570
|
return {k: truncate_for_logging(v) for k, v in obj.items()}
|
|
554
|
-
|
|
571
|
+
if isinstance(obj, list):
|
|
555
572
|
if len(obj) > max_items:
|
|
556
573
|
return [truncate_for_logging(item) for item in obj[:max_items]] + [
|
|
557
574
|
f"... ({len(obj) - max_items} more items)"
|
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
"""This module sets up OpenTelemetry tracing for a service."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
import sys
|
|
4
5
|
|
|
5
6
|
from opentelemetry import trace
|
|
6
7
|
from opentelemetry.sdk.resources import Resource
|
|
7
8
|
from opentelemetry.sdk.trace import TracerProvider
|
|
8
9
|
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
|
|
9
|
-
from temporalio import workflow
|
|
10
10
|
|
|
11
|
-
from
|
|
11
|
+
# from temporalio import workflow
|
|
12
|
+
from flock.logging.span_middleware.baggage_span_processor import (
|
|
12
13
|
BaggageAttributeSpanProcessor,
|
|
13
14
|
)
|
|
15
|
+
from flock.logging.telemetry_exporter.duckdb_exporter import (
|
|
16
|
+
DuckDBSpanExporter,
|
|
17
|
+
)
|
|
14
18
|
|
|
15
|
-
with workflow.unsafe.imports_passed_through():
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
# with workflow.unsafe.imports_passed_through():
|
|
20
|
+
from flock.logging.telemetry_exporter.file_exporter import (
|
|
21
|
+
FileSpanExporter,
|
|
22
|
+
)
|
|
23
|
+
from flock.logging.telemetry_exporter.sqlite_exporter import (
|
|
24
|
+
SqliteTelemetryExporter,
|
|
25
|
+
)
|
|
22
26
|
|
|
23
27
|
|
|
24
28
|
class TelemetryConfig:
|
|
@@ -39,9 +43,12 @@ class TelemetryConfig:
|
|
|
39
43
|
local_logging_dir: str | None = None,
|
|
40
44
|
file_export_name: str | None = None,
|
|
41
45
|
sqlite_db_name: str | None = None,
|
|
46
|
+
duckdb_name: str | None = None,
|
|
47
|
+
duckdb_ttl_days: int | None = None,
|
|
42
48
|
enable_jaeger: bool = True,
|
|
43
49
|
enable_file: bool = True,
|
|
44
50
|
enable_sql: bool = True,
|
|
51
|
+
enable_duckdb: bool = True,
|
|
45
52
|
enable_otlp: bool = True,
|
|
46
53
|
otlp_protocol: str = "grpc",
|
|
47
54
|
otlp_endpoint: str = "http://localhost:4317",
|
|
@@ -52,6 +59,7 @@ class TelemetryConfig:
|
|
|
52
59
|
:param jaeger_endpoint: The Jaeger collector gRPC endpoint (e.g., "localhost:14250").
|
|
53
60
|
:param file_export_path: If provided, spans will be written to this file.
|
|
54
61
|
:param sqlite_db_path: If provided, spans will be stored in this SQLite DB.
|
|
62
|
+
:param duckdb_ttl_days: Delete traces older than this many days (default: None = keep forever).
|
|
55
63
|
:param batch_processor_options: Dict of options for BatchSpanProcessor (e.g., {"max_export_batch_size": 10}).
|
|
56
64
|
"""
|
|
57
65
|
self.service_name = service_name
|
|
@@ -59,18 +67,50 @@ class TelemetryConfig:
|
|
|
59
67
|
self.jaeger_transport = jaeger_transport
|
|
60
68
|
self.file_export_name = file_export_name
|
|
61
69
|
self.sqlite_db_name = sqlite_db_name
|
|
70
|
+
self.duckdb_name = duckdb_name
|
|
71
|
+
self.duckdb_ttl_days = duckdb_ttl_days
|
|
62
72
|
self.local_logging_dir = local_logging_dir
|
|
63
73
|
self.batch_processor_options = batch_processor_options or {}
|
|
64
74
|
self.enable_jaeger = enable_jaeger
|
|
65
75
|
self.enable_file = enable_file
|
|
66
76
|
self.enable_sql = enable_sql
|
|
77
|
+
self.enable_duckdb = enable_duckdb
|
|
67
78
|
self.enable_otlp = enable_otlp
|
|
68
79
|
self.otlp_protocol = otlp_protocol
|
|
69
80
|
self.otlp_endpoint = otlp_endpoint
|
|
70
81
|
self.global_tracer = None
|
|
82
|
+
self._configured: bool = False
|
|
83
|
+
|
|
84
|
+
def _should_setup(self) -> bool:
|
|
85
|
+
# Respect explicit disable flag for tests and minimal setups
|
|
86
|
+
if os.environ.get("FLOCK_DISABLE_TELEMETRY_AUTOSETUP", "").lower() in {
|
|
87
|
+
"1",
|
|
88
|
+
"true",
|
|
89
|
+
"yes",
|
|
90
|
+
"on",
|
|
91
|
+
}:
|
|
92
|
+
return False
|
|
93
|
+
try:
|
|
94
|
+
# If a provider is already installed (typically by user/tests), don't override it
|
|
95
|
+
from opentelemetry.sdk.trace import (
|
|
96
|
+
TracerProvider as SDKTracerProvider, # type: ignore
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
current = trace.get_tracer_provider()
|
|
100
|
+
if isinstance(current, SDKTracerProvider):
|
|
101
|
+
return False
|
|
102
|
+
except Exception:
|
|
103
|
+
# If SDK isn't available or introspection fails, fall back to enabling
|
|
104
|
+
pass
|
|
105
|
+
return True
|
|
71
106
|
|
|
72
107
|
def setup_tracing(self):
|
|
73
108
|
"""Set up OpenTelemetry tracing with the specified exporters."""
|
|
109
|
+
if self._configured:
|
|
110
|
+
return
|
|
111
|
+
if not self._should_setup():
|
|
112
|
+
return
|
|
113
|
+
|
|
74
114
|
# Create a Resource with the service name.
|
|
75
115
|
resource = Resource(attributes={"service.name": self.service_name})
|
|
76
116
|
provider = TracerProvider(resource=resource)
|
|
@@ -97,13 +137,10 @@ class TelemetryConfig:
|
|
|
97
137
|
collector_endpoint=self.jaeger_endpoint,
|
|
98
138
|
)
|
|
99
139
|
else:
|
|
100
|
-
raise ValueError(
|
|
101
|
-
"Invalid JAEGER_TRANSPORT specified. Use 'grpc' or 'http'."
|
|
102
|
-
)
|
|
140
|
+
raise ValueError("Invalid JAEGER_TRANSPORT specified. Use 'grpc' or 'http'.")
|
|
103
141
|
|
|
104
142
|
span_processors.append(SimpleSpanProcessor(jaeger_exporter))
|
|
105
143
|
|
|
106
|
-
|
|
107
144
|
if self.enable_otlp:
|
|
108
145
|
if self.otlp_protocol == "grpc":
|
|
109
146
|
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
|
@@ -131,18 +168,21 @@ class TelemetryConfig:
|
|
|
131
168
|
|
|
132
169
|
# If a file path is provided, add the custom file exporter.
|
|
133
170
|
if self.file_export_name and self.enable_file:
|
|
134
|
-
file_exporter = FileSpanExporter(
|
|
135
|
-
self.local_logging_dir, self.file_export_name
|
|
136
|
-
)
|
|
171
|
+
file_exporter = FileSpanExporter(self.local_logging_dir, self.file_export_name)
|
|
137
172
|
span_processors.append(SimpleSpanProcessor(file_exporter))
|
|
138
173
|
|
|
139
174
|
# If a SQLite database path is provided, ensure the DB exists and add the SQLite exporter.
|
|
140
175
|
if self.sqlite_db_name and self.enable_sql:
|
|
141
|
-
sqlite_exporter = SqliteTelemetryExporter(
|
|
142
|
-
self.local_logging_dir, self.sqlite_db_name
|
|
143
|
-
)
|
|
176
|
+
sqlite_exporter = SqliteTelemetryExporter(self.local_logging_dir, self.sqlite_db_name)
|
|
144
177
|
span_processors.append(SimpleSpanProcessor(sqlite_exporter))
|
|
145
178
|
|
|
179
|
+
# If a DuckDB database path is provided, add the DuckDB exporter.
|
|
180
|
+
if self.duckdb_name and self.enable_duckdb:
|
|
181
|
+
duckdb_exporter = DuckDBSpanExporter(
|
|
182
|
+
self.local_logging_dir, self.duckdb_name, ttl_days=self.duckdb_ttl_days
|
|
183
|
+
)
|
|
184
|
+
span_processors.append(SimpleSpanProcessor(duckdb_exporter))
|
|
185
|
+
|
|
146
186
|
# Register all span processors with the provider.
|
|
147
187
|
for processor in span_processors:
|
|
148
188
|
provider.add_span_processor(processor)
|
|
@@ -150,8 +190,9 @@ class TelemetryConfig:
|
|
|
150
190
|
provider.add_span_processor(
|
|
151
191
|
BaggageAttributeSpanProcessor(baggage_keys=["session_id", "run_id"])
|
|
152
192
|
)
|
|
153
|
-
|
|
193
|
+
self.global_tracer = trace.get_tracer("flock")
|
|
154
194
|
sys.excepthook = self.log_exception_to_otel
|
|
195
|
+
self._configured = True
|
|
155
196
|
|
|
156
197
|
def log_exception_to_otel(self, exc_type, exc_value, exc_traceback):
|
|
157
198
|
"""Log unhandled exceptions to OpenTelemetry."""
|
|
@@ -160,11 +201,10 @@ class TelemetryConfig:
|
|
|
160
201
|
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
|
161
202
|
return
|
|
162
203
|
|
|
204
|
+
if not self.global_tracer:
|
|
205
|
+
return
|
|
206
|
+
|
|
163
207
|
# Use OpenTelemetry to record the exception
|
|
164
|
-
with self.global_tracer.start_as_current_span(
|
|
165
|
-
"UnhandledException"
|
|
166
|
-
) as span:
|
|
208
|
+
with self.global_tracer.start_as_current_span("UnhandledException") as span:
|
|
167
209
|
span.record_exception(exc_value)
|
|
168
|
-
span.set_status(
|
|
169
|
-
trace.Status(trace.StatusCode.ERROR, str(exc_value))
|
|
170
|
-
)
|
|
210
|
+
span.set_status(trace.Status(trace.StatusCode.ERROR, str(exc_value)))
|
|
@@ -25,14 +25,14 @@ class TelemetryExporter(SpanExporter, ABC):
|
|
|
25
25
|
self.shutdown()
|
|
26
26
|
|
|
27
27
|
@abstractmethod
|
|
28
|
-
def export(self, spans) -> SpanExportResult
|
|
28
|
+
def export(self, spans) -> SpanExportResult: # type: ignore[override]
|
|
29
29
|
"""Export spans to the configured backend.
|
|
30
30
|
|
|
31
31
|
To be implemented by subclasses.
|
|
32
|
+
May return SUCCESS, FAILURE, or None (handled by _export wrapper).
|
|
32
33
|
"""
|
|
33
34
|
raise NotImplementedError("Subclasses must implement the export method")
|
|
34
35
|
|
|
35
36
|
@abstractmethod
|
|
36
37
|
def shutdown(self):
|
|
37
38
|
"""Cleanup resources, if any. Optional for subclasses."""
|
|
38
|
-
pass
|