flock-core 0.4.542__py3-none-any.whl → 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flock-core might be problematic. Click here for more details.
- flock/__init__.py +12 -217
- flock/agent.py +1079 -0
- flock/api/themes.py +71 -0
- flock/artifacts.py +86 -0
- flock/cli.py +147 -0
- flock/components.py +189 -0
- flock/dashboard/__init__.py +30 -0
- flock/dashboard/collector.py +559 -0
- flock/dashboard/events.py +188 -0
- flock/dashboard/graph_builder.py +563 -0
- flock/dashboard/launcher.py +235 -0
- flock/dashboard/models/graph.py +156 -0
- flock/dashboard/service.py +991 -0
- flock/dashboard/static_v2/assets/index-DFRnI_mt.js +111 -0
- flock/dashboard/static_v2/assets/index-fPLNdmp1.css +1 -0
- flock/dashboard/static_v2/index.html +13 -0
- flock/dashboard/websocket.py +246 -0
- flock/engines/__init__.py +6 -0
- flock/engines/dspy_engine.py +932 -0
- flock/examples.py +131 -0
- flock/frontend/README.md +778 -0
- flock/frontend/docs/DESIGN_SYSTEM.md +1980 -0
- flock/frontend/index.html +12 -0
- flock/frontend/package-lock.json +4337 -0
- flock/frontend/package.json +48 -0
- flock/frontend/src/App.tsx +139 -0
- flock/frontend/src/__tests__/integration/graph-snapshot.test.tsx +647 -0
- flock/frontend/src/__tests__/integration/indexeddb-persistence.test.tsx +699 -0
- flock/frontend/src/components/common/BuildInfo.tsx +39 -0
- flock/frontend/src/components/common/EmptyState.module.css +115 -0
- flock/frontend/src/components/common/EmptyState.tsx +128 -0
- flock/frontend/src/components/common/ErrorBoundary.module.css +169 -0
- flock/frontend/src/components/common/ErrorBoundary.tsx +118 -0
- flock/frontend/src/components/common/KeyboardShortcutsDialog.css +251 -0
- flock/frontend/src/components/common/KeyboardShortcutsDialog.tsx +151 -0
- flock/frontend/src/components/common/LoadingSpinner.module.css +97 -0
- flock/frontend/src/components/common/LoadingSpinner.tsx +29 -0
- flock/frontend/src/components/controls/PublishControl.css +547 -0
- flock/frontend/src/components/controls/PublishControl.test.tsx +543 -0
- flock/frontend/src/components/controls/PublishControl.tsx +432 -0
- flock/frontend/src/components/details/DetailWindowContainer.tsx +58 -0
- flock/frontend/src/components/details/LiveOutputTab.test.tsx +792 -0
- flock/frontend/src/components/details/LiveOutputTab.tsx +220 -0
- flock/frontend/src/components/details/MessageDetailWindow.tsx +439 -0
- flock/frontend/src/components/details/MessageHistoryTab.tsx +374 -0
- flock/frontend/src/components/details/NodeDetailWindow.test.tsx +501 -0
- flock/frontend/src/components/details/NodeDetailWindow.tsx +218 -0
- flock/frontend/src/components/details/RunStatusTab.tsx +348 -0
- flock/frontend/src/components/details/tabs.test.tsx +1015 -0
- flock/frontend/src/components/filters/ArtifactTypeFilter.tsx +21 -0
- flock/frontend/src/components/filters/CorrelationIDFilter.module.css +102 -0
- flock/frontend/src/components/filters/CorrelationIDFilter.test.tsx +197 -0
- flock/frontend/src/components/filters/CorrelationIDFilter.tsx +121 -0
- flock/frontend/src/components/filters/FilterFlyout.module.css +104 -0
- flock/frontend/src/components/filters/FilterFlyout.tsx +80 -0
- flock/frontend/src/components/filters/FilterPills.module.css +220 -0
- flock/frontend/src/components/filters/FilterPills.test.tsx +189 -0
- flock/frontend/src/components/filters/FilterPills.tsx +143 -0
- flock/frontend/src/components/filters/ProducerFilter.tsx +21 -0
- flock/frontend/src/components/filters/SavedFiltersControl.module.css +60 -0
- flock/frontend/src/components/filters/SavedFiltersControl.test.tsx +158 -0
- flock/frontend/src/components/filters/SavedFiltersControl.tsx +159 -0
- flock/frontend/src/components/filters/TagFilter.tsx +21 -0
- flock/frontend/src/components/filters/TimeRangeFilter.module.css +115 -0
- flock/frontend/src/components/filters/TimeRangeFilter.test.tsx +154 -0
- flock/frontend/src/components/filters/TimeRangeFilter.tsx +110 -0
- flock/frontend/src/components/filters/VisibilityFilter.tsx +21 -0
- flock/frontend/src/components/graph/AgentNode.test.tsx +77 -0
- flock/frontend/src/components/graph/AgentNode.tsx +324 -0
- flock/frontend/src/components/graph/GraphCanvas.tsx +613 -0
- flock/frontend/src/components/graph/MessageFlowEdge.tsx +128 -0
- flock/frontend/src/components/graph/MessageNode.test.tsx +64 -0
- flock/frontend/src/components/graph/MessageNode.tsx +129 -0
- flock/frontend/src/components/graph/MiniMap.tsx +47 -0
- flock/frontend/src/components/graph/TransformEdge.tsx +123 -0
- flock/frontend/src/components/layout/DashboardLayout.css +420 -0
- flock/frontend/src/components/layout/DashboardLayout.tsx +287 -0
- flock/frontend/src/components/layout/Header.module.css +88 -0
- flock/frontend/src/components/layout/Header.tsx +52 -0
- flock/frontend/src/components/modules/HistoricalArtifactsModule.module.css +288 -0
- flock/frontend/src/components/modules/HistoricalArtifactsModule.tsx +450 -0
- flock/frontend/src/components/modules/HistoricalArtifactsModuleWrapper.tsx +13 -0
- flock/frontend/src/components/modules/JsonAttributeRenderer.tsx +140 -0
- flock/frontend/src/components/modules/ModuleRegistry.test.ts +333 -0
- flock/frontend/src/components/modules/ModuleRegistry.ts +93 -0
- flock/frontend/src/components/modules/ModuleWindow.tsx +223 -0
- flock/frontend/src/components/modules/TraceModuleJaeger.tsx +1971 -0
- flock/frontend/src/components/modules/TraceModuleJaegerWrapper.tsx +13 -0
- flock/frontend/src/components/modules/registerModules.ts +29 -0
- flock/frontend/src/components/settings/AdvancedSettings.tsx +175 -0
- flock/frontend/src/components/settings/AppearanceSettings.tsx +185 -0
- flock/frontend/src/components/settings/GraphSettings.tsx +110 -0
- flock/frontend/src/components/settings/MultiSelect.tsx +235 -0
- flock/frontend/src/components/settings/SettingsPanel.css +327 -0
- flock/frontend/src/components/settings/SettingsPanel.tsx +131 -0
- flock/frontend/src/components/settings/ThemeSelector.tsx +298 -0
- flock/frontend/src/components/settings/TracingSettings.tsx +404 -0
- flock/frontend/src/hooks/useKeyboardShortcuts.ts +148 -0
- flock/frontend/src/hooks/useModulePersistence.test.ts +442 -0
- flock/frontend/src/hooks/useModulePersistence.ts +154 -0
- flock/frontend/src/hooks/useModules.ts +157 -0
- flock/frontend/src/hooks/usePersistence.ts +141 -0
- flock/frontend/src/main.tsx +13 -0
- flock/frontend/src/services/api.ts +337 -0
- flock/frontend/src/services/graphService.test.ts +330 -0
- flock/frontend/src/services/graphService.ts +75 -0
- flock/frontend/src/services/indexeddb.test.ts +793 -0
- flock/frontend/src/services/indexeddb.ts +848 -0
- flock/frontend/src/services/layout.test.ts +437 -0
- flock/frontend/src/services/layout.ts +357 -0
- flock/frontend/src/services/themeApplicator.ts +140 -0
- flock/frontend/src/services/themeService.ts +77 -0
- flock/frontend/src/services/websocket.ts +650 -0
- flock/frontend/src/store/filterStore.test.ts +250 -0
- flock/frontend/src/store/filterStore.ts +272 -0
- flock/frontend/src/store/graphStore.test.ts +570 -0
- flock/frontend/src/store/graphStore.ts +462 -0
- flock/frontend/src/store/moduleStore.test.ts +253 -0
- flock/frontend/src/store/moduleStore.ts +75 -0
- flock/frontend/src/store/settingsStore.ts +188 -0
- flock/frontend/src/store/streamStore.ts +68 -0
- flock/frontend/src/store/uiStore.test.ts +54 -0
- flock/frontend/src/store/uiStore.ts +122 -0
- flock/frontend/src/store/wsStore.ts +34 -0
- flock/frontend/src/styles/index.css +15 -0
- flock/frontend/src/styles/scrollbar.css +47 -0
- flock/frontend/src/styles/variables.css +488 -0
- flock/frontend/src/test/setup.ts +1 -0
- flock/frontend/src/types/filters.ts +47 -0
- flock/frontend/src/types/graph.ts +95 -0
- flock/frontend/src/types/modules.ts +10 -0
- flock/frontend/src/types/theme.ts +55 -0
- flock/frontend/src/utils/artifacts.ts +24 -0
- flock/frontend/src/utils/mockData.ts +98 -0
- flock/frontend/src/utils/performance.ts +16 -0
- flock/frontend/src/vite-env.d.ts +17 -0
- flock/frontend/tsconfig.json +27 -0
- flock/frontend/tsconfig.node.json +11 -0
- flock/frontend/vite.config.ts +25 -0
- flock/frontend/vitest.config.ts +11 -0
- flock/{core/util → helper}/cli_helper.py +9 -5
- flock/{core/logging → logging}/__init__.py +2 -3
- flock/logging/auto_trace.py +159 -0
- flock/{core/logging → logging}/formatters/enum_builder.py +3 -4
- flock/{core/logging → logging}/formatters/theme_builder.py +19 -44
- flock/{core/logging → logging}/formatters/themed_formatter.py +69 -107
- flock/{core/logging → logging}/logging.py +78 -61
- flock/{core/logging → logging}/telemetry.py +66 -26
- flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
- flock/logging/telemetry_exporter/duckdb_exporter.py +216 -0
- flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +13 -10
- flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
- flock/logging/trace_and_logged.py +304 -0
- flock/mcp/__init__.py +91 -0
- flock/{core/mcp/mcp_client.py → mcp/client.py} +131 -158
- flock/{core/mcp/mcp_config.py → mcp/config.py} +86 -132
- flock/mcp/manager.py +286 -0
- flock/mcp/servers/sse/__init__.py +1 -1
- flock/mcp/servers/sse/flock_sse_server.py +16 -58
- flock/mcp/servers/stdio/__init__.py +1 -1
- flock/mcp/servers/stdio/flock_stdio_server.py +13 -53
- flock/mcp/servers/streamable_http/flock_streamable_http_server.py +22 -67
- flock/mcp/servers/websockets/flock_websocket_server.py +12 -45
- flock/{core/mcp/flock_mcp_tool_base.py → mcp/tool.py} +24 -78
- flock/mcp/types/__init__.py +42 -0
- flock/{core/mcp → mcp}/types/callbacks.py +12 -15
- flock/{core/mcp → mcp}/types/factories.py +7 -6
- flock/{core/mcp → mcp}/types/handlers.py +13 -18
- flock/{core/mcp → mcp}/types/types.py +70 -74
- flock/{core/mcp → mcp}/util/helpers.py +3 -3
- flock/orchestrator.py +970 -0
- flock/registry.py +148 -0
- flock/runtime.py +262 -0
- flock/service.py +277 -0
- flock/store.py +1214 -0
- flock/subscription.py +111 -0
- flock/themes/andromeda.toml +1 -1
- flock/themes/apple-system-colors.toml +1 -1
- flock/themes/arcoiris.toml +1 -1
- flock/themes/atomonelight.toml +1 -1
- flock/themes/ayu copy.toml +1 -1
- flock/themes/ayu-light.toml +1 -1
- flock/themes/belafonte-day.toml +1 -1
- flock/themes/belafonte-night.toml +1 -1
- flock/themes/blulocodark.toml +1 -1
- flock/themes/breeze.toml +1 -1
- flock/themes/broadcast.toml +1 -1
- flock/themes/brogrammer.toml +1 -1
- flock/themes/builtin-dark.toml +1 -1
- flock/themes/builtin-pastel-dark.toml +1 -1
- flock/themes/catppuccin-latte.toml +1 -1
- flock/themes/catppuccin-macchiato.toml +1 -1
- flock/themes/catppuccin-mocha.toml +1 -1
- flock/themes/cga.toml +1 -1
- flock/themes/chalk.toml +1 -1
- flock/themes/ciapre.toml +1 -1
- flock/themes/coffee-theme.toml +1 -1
- flock/themes/cyberpunkscarletprotocol.toml +1 -1
- flock/themes/dark+.toml +1 -1
- flock/themes/darkermatrix.toml +1 -1
- flock/themes/darkmatrix.toml +2 -2
- flock/themes/darkside.toml +1 -1
- flock/themes/deep.toml +2 -2
- flock/themes/desert.toml +1 -1
- flock/themes/django.toml +1 -1
- flock/themes/djangosmooth.toml +1 -1
- flock/themes/doomone.toml +1 -1
- flock/themes/dotgov.toml +1 -1
- flock/themes/dracula+.toml +1 -1
- flock/themes/duckbones.toml +1 -1
- flock/themes/encom.toml +1 -1
- flock/themes/espresso.toml +1 -1
- flock/themes/everblush.toml +1 -1
- flock/themes/fairyfloss.toml +1 -1
- flock/themes/fideloper.toml +1 -1
- flock/themes/fishtank.toml +1 -1
- flock/themes/flexoki-light.toml +1 -1
- flock/themes/floraverse.toml +1 -1
- flock/themes/framer.toml +1 -1
- flock/themes/galizur.toml +1 -1
- flock/themes/github.toml +1 -1
- flock/themes/grass.toml +1 -1
- flock/themes/grey-green.toml +1 -1
- flock/themes/gruvboxlight.toml +1 -1
- flock/themes/guezwhoz.toml +1 -1
- flock/themes/harper.toml +1 -1
- flock/themes/hax0r-blue.toml +1 -1
- flock/themes/hopscotch.256.toml +1 -1
- flock/themes/ic-green-ppl.toml +1 -1
- flock/themes/iceberg-dark.toml +1 -1
- flock/themes/japanesque.toml +1 -1
- flock/themes/jubi.toml +1 -1
- flock/themes/kibble.toml +1 -1
- flock/themes/kolorit.toml +1 -1
- flock/themes/kurokula.toml +1 -1
- flock/themes/materialdesigncolors.toml +1 -1
- flock/themes/matrix.toml +1 -1
- flock/themes/mellifluous.toml +1 -1
- flock/themes/midnight-in-mojave.toml +1 -1
- flock/themes/monokai-remastered.toml +1 -1
- flock/themes/monokai-soda.toml +1 -1
- flock/themes/neon.toml +1 -1
- flock/themes/neopolitan.toml +5 -5
- flock/themes/nord-light.toml +1 -1
- flock/themes/ocean.toml +1 -1
- flock/themes/onehalfdark.toml +1 -1
- flock/themes/onehalflight.toml +1 -1
- flock/themes/palenighthc.toml +1 -1
- flock/themes/paulmillr.toml +1 -1
- flock/themes/pencildark.toml +1 -1
- flock/themes/pnevma.toml +1 -1
- flock/themes/purple-rain.toml +1 -1
- flock/themes/purplepeter.toml +1 -1
- flock/themes/raycast-dark.toml +1 -1
- flock/themes/red-sands.toml +1 -1
- flock/themes/relaxed.toml +1 -1
- flock/themes/retro.toml +1 -1
- flock/themes/rose-pine.toml +1 -1
- flock/themes/royal.toml +1 -1
- flock/themes/ryuuko.toml +1 -1
- flock/themes/sakura.toml +1 -1
- flock/themes/scarlet-protocol.toml +1 -1
- flock/themes/seoulbones-dark.toml +1 -1
- flock/themes/shades-of-purple.toml +1 -1
- flock/themes/smyck.toml +1 -1
- flock/themes/softserver.toml +1 -1
- flock/themes/solarized-darcula.toml +1 -1
- flock/themes/square.toml +1 -1
- flock/themes/sugarplum.toml +1 -1
- flock/themes/thayer-bright.toml +1 -1
- flock/themes/tokyonight.toml +1 -1
- flock/themes/tomorrow.toml +1 -1
- flock/themes/ubuntu.toml +1 -1
- flock/themes/ultradark.toml +1 -1
- flock/themes/ultraviolent.toml +1 -1
- flock/themes/unikitty.toml +1 -1
- flock/themes/urple.toml +1 -1
- flock/themes/vesper.toml +1 -1
- flock/themes/vimbones.toml +1 -1
- flock/themes/wildcherry.toml +1 -1
- flock/themes/wilmersdorf.toml +1 -1
- flock/themes/wryan.toml +1 -1
- flock/themes/xcodedarkhc.toml +1 -1
- flock/themes/xcodelight.toml +1 -1
- flock/themes/zenbones-light.toml +1 -1
- flock/themes/zenwritten-dark.toml +1 -1
- flock/utilities.py +301 -0
- flock/utility/output_utility_component.py +226 -0
- flock/visibility.py +107 -0
- flock_core-0.5.0.dist-info/METADATA +964 -0
- flock_core-0.5.0.dist-info/RECORD +525 -0
- flock_core-0.5.0.dist-info/entry_points.txt +2 -0
- {flock_core-0.4.542.dist-info → flock_core-0.5.0.dist-info}/licenses/LICENSE +1 -1
- flock/adapter/__init__.py +0 -14
- flock/adapter/azure_adapter.py +0 -68
- flock/adapter/chroma_adapter.py +0 -73
- flock/adapter/faiss_adapter.py +0 -97
- flock/adapter/pinecone_adapter.py +0 -51
- flock/adapter/vector_base.py +0 -47
- flock/cli/assets/release_notes.md +0 -140
- flock/cli/config.py +0 -8
- flock/cli/constants.py +0 -36
- flock/cli/create_agent.py +0 -1
- flock/cli/create_flock.py +0 -280
- flock/cli/execute_flock.py +0 -620
- flock/cli/load_agent.py +0 -1
- flock/cli/load_examples.py +0 -1
- flock/cli/load_flock.py +0 -192
- flock/cli/load_release_notes.py +0 -20
- flock/cli/loaded_flock_cli.py +0 -254
- flock/cli/manage_agents.py +0 -459
- flock/cli/registry_management.py +0 -889
- flock/cli/runner.py +0 -41
- flock/cli/settings.py +0 -857
- flock/cli/utils.py +0 -135
- flock/cli/view_results.py +0 -29
- flock/cli/yaml_editor.py +0 -396
- flock/config.py +0 -56
- flock/core/__init__.py +0 -44
- flock/core/api/__init__.py +0 -10
- flock/core/api/custom_endpoint.py +0 -45
- flock/core/api/endpoints.py +0 -262
- flock/core/api/main.py +0 -162
- flock/core/api/models.py +0 -101
- flock/core/api/run_store.py +0 -224
- flock/core/api/runner.py +0 -44
- flock/core/api/service.py +0 -214
- flock/core/config/flock_agent_config.py +0 -11
- flock/core/config/scheduled_agent_config.py +0 -40
- flock/core/context/context.py +0 -214
- flock/core/context/context_manager.py +0 -40
- flock/core/context/context_vars.py +0 -11
- flock/core/evaluation/utils.py +0 -395
- flock/core/execution/batch_executor.py +0 -369
- flock/core/execution/evaluation_executor.py +0 -438
- flock/core/execution/local_executor.py +0 -31
- flock/core/execution/opik_executor.py +0 -103
- flock/core/execution/temporal_executor.py +0 -166
- flock/core/flock.py +0 -1003
- flock/core/flock_agent.py +0 -1258
- flock/core/flock_evaluator.py +0 -60
- flock/core/flock_factory.py +0 -513
- flock/core/flock_module.py +0 -207
- flock/core/flock_registry.py +0 -702
- flock/core/flock_router.py +0 -83
- flock/core/flock_scheduler.py +0 -166
- flock/core/flock_server_manager.py +0 -136
- flock/core/interpreter/python_interpreter.py +0 -689
- flock/core/logging/live_capture.py +0 -137
- flock/core/logging/trace_and_logged.py +0 -59
- flock/core/mcp/__init__.py +0 -1
- flock/core/mcp/flock_mcp_server.py +0 -640
- flock/core/mcp/mcp_client_manager.py +0 -201
- flock/core/mcp/types/__init__.py +0 -1
- flock/core/mixin/dspy_integration.py +0 -445
- flock/core/mixin/prompt_parser.py +0 -125
- flock/core/serialization/__init__.py +0 -13
- flock/core/serialization/callable_registry.py +0 -52
- flock/core/serialization/flock_serializer.py +0 -854
- flock/core/serialization/json_encoder.py +0 -41
- flock/core/serialization/secure_serializer.py +0 -175
- flock/core/serialization/serializable.py +0 -342
- flock/core/serialization/serialization_utils.py +0 -409
- flock/core/util/file_path_utils.py +0 -223
- flock/core/util/hydrator.py +0 -309
- flock/core/util/input_resolver.py +0 -141
- flock/core/util/loader.py +0 -59
- flock/core/util/splitter.py +0 -219
- flock/di.py +0 -41
- flock/evaluators/__init__.py +0 -1
- flock/evaluators/declarative/__init__.py +0 -1
- flock/evaluators/declarative/declarative_evaluator.py +0 -217
- flock/evaluators/memory/memory_evaluator.py +0 -90
- flock/evaluators/test/test_case_evaluator.py +0 -38
- flock/evaluators/zep/zep_evaluator.py +0 -59
- flock/modules/__init__.py +0 -1
- flock/modules/assertion/__init__.py +0 -1
- flock/modules/assertion/assertion_module.py +0 -286
- flock/modules/callback/__init__.py +0 -1
- flock/modules/callback/callback_module.py +0 -91
- flock/modules/enterprise_memory/README.md +0 -99
- flock/modules/enterprise_memory/enterprise_memory_module.py +0 -526
- flock/modules/mem0/__init__.py +0 -1
- flock/modules/mem0/mem0_module.py +0 -126
- flock/modules/mem0_async/__init__.py +0 -1
- flock/modules/mem0_async/async_mem0_module.py +0 -126
- flock/modules/memory/__init__.py +0 -1
- flock/modules/memory/memory_module.py +0 -429
- flock/modules/memory/memory_parser.py +0 -125
- flock/modules/memory/memory_storage.py +0 -736
- flock/modules/output/__init__.py +0 -1
- flock/modules/output/output_module.py +0 -196
- flock/modules/performance/__init__.py +0 -1
- flock/modules/performance/metrics_module.py +0 -678
- flock/modules/zep/__init__.py +0 -1
- flock/modules/zep/zep_module.py +0 -192
- flock/platform/docker_tools.py +0 -49
- flock/platform/jaeger_install.py +0 -86
- flock/routers/__init__.py +0 -1
- flock/routers/agent/__init__.py +0 -1
- flock/routers/agent/agent_router.py +0 -236
- flock/routers/agent/handoff_agent.py +0 -58
- flock/routers/conditional/conditional_router.py +0 -486
- flock/routers/default/__init__.py +0 -1
- flock/routers/default/default_router.py +0 -80
- flock/routers/feedback/feedback_router.py +0 -114
- flock/routers/list_generator/list_generator_router.py +0 -166
- flock/routers/llm/__init__.py +0 -1
- flock/routers/llm/llm_router.py +0 -365
- flock/tools/__init__.py +0 -0
- flock/tools/azure_tools.py +0 -781
- flock/tools/code_tools.py +0 -167
- flock/tools/file_tools.py +0 -149
- flock/tools/github_tools.py +0 -157
- flock/tools/markdown_tools.py +0 -205
- flock/tools/system_tools.py +0 -9
- flock/tools/text_tools.py +0 -810
- flock/tools/web_tools.py +0 -92
- flock/tools/zendesk_tools.py +0 -501
- flock/webapp/__init__.py +0 -1
- flock/webapp/app/__init__.py +0 -0
- flock/webapp/app/api/__init__.py +0 -0
- flock/webapp/app/api/agent_management.py +0 -237
- flock/webapp/app/api/execution.py +0 -503
- flock/webapp/app/api/flock_management.py +0 -125
- flock/webapp/app/api/registry_viewer.py +0 -29
- flock/webapp/app/chat.py +0 -662
- flock/webapp/app/config.py +0 -104
- flock/webapp/app/dependencies.py +0 -117
- flock/webapp/app/main.py +0 -1086
- flock/webapp/app/middleware.py +0 -113
- flock/webapp/app/models_ui.py +0 -7
- flock/webapp/app/services/__init__.py +0 -0
- flock/webapp/app/services/feedback_file_service.py +0 -363
- flock/webapp/app/services/flock_service.py +0 -345
- flock/webapp/app/services/sharing_models.py +0 -81
- flock/webapp/app/services/sharing_store.py +0 -597
- flock/webapp/app/templates/theme_mapper.html +0 -326
- flock/webapp/app/theme_mapper.py +0 -811
- flock/webapp/app/utils.py +0 -85
- flock/webapp/run.py +0 -219
- flock/webapp/static/css/chat.css +0 -301
- flock/webapp/static/css/components.css +0 -167
- flock/webapp/static/css/header.css +0 -39
- flock/webapp/static/css/layout.css +0 -281
- flock/webapp/static/css/sidebar.css +0 -127
- flock/webapp/static/css/two-pane.css +0 -48
- flock/webapp/templates/base.html +0 -389
- flock/webapp/templates/chat.html +0 -152
- flock/webapp/templates/chat_settings.html +0 -19
- flock/webapp/templates/flock_editor.html +0 -16
- flock/webapp/templates/index.html +0 -12
- flock/webapp/templates/partials/_agent_detail_form.html +0 -93
- flock/webapp/templates/partials/_agent_list.html +0 -18
- flock/webapp/templates/partials/_agent_manager_view.html +0 -51
- flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
- flock/webapp/templates/partials/_chat_container.html +0 -15
- flock/webapp/templates/partials/_chat_messages.html +0 -57
- flock/webapp/templates/partials/_chat_settings_form.html +0 -85
- flock/webapp/templates/partials/_create_flock_form.html +0 -50
- flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
- flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
- flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
- flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
- flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
- flock/webapp/templates/partials/_env_vars_table.html +0 -23
- flock/webapp/templates/partials/_execution_form.html +0 -127
- flock/webapp/templates/partials/_execution_view_container.html +0 -28
- flock/webapp/templates/partials/_flock_file_list.html +0 -23
- flock/webapp/templates/partials/_flock_properties_form.html +0 -52
- flock/webapp/templates/partials/_flock_upload_form.html +0 -16
- flock/webapp/templates/partials/_header_flock_status.html +0 -5
- flock/webapp/templates/partials/_live_logs.html +0 -13
- flock/webapp/templates/partials/_load_manager_view.html +0 -49
- flock/webapp/templates/partials/_registry_table.html +0 -25
- flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
- flock/webapp/templates/partials/_results_display.html +0 -78
- flock/webapp/templates/partials/_settings_env_content.html +0 -9
- flock/webapp/templates/partials/_settings_theme_content.html +0 -14
- flock/webapp/templates/partials/_settings_view.html +0 -36
- flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
- flock/webapp/templates/partials/_share_link_snippet.html +0 -35
- flock/webapp/templates/partials/_sidebar.html +0 -74
- flock/webapp/templates/partials/_structured_data_view.html +0 -40
- flock/webapp/templates/partials/_theme_preview.html +0 -36
- flock/webapp/templates/registry_viewer.html +0 -84
- flock/webapp/templates/shared_run_page.html +0 -140
- flock/workflow/__init__.py +0 -0
- flock/workflow/activities.py +0 -237
- flock/workflow/agent_activities.py +0 -24
- flock/workflow/agent_execution_activity.py +0 -240
- flock/workflow/flock_workflow.py +0 -225
- flock/workflow/temporal_config.py +0 -96
- flock/workflow/temporal_setup.py +0 -60
- flock_core-0.4.542.dist-info/METADATA +0 -676
- flock_core-0.4.542.dist-info/RECORD +0 -572
- flock_core-0.4.542.dist-info/entry_points.txt +0 -2
- /flock/{core/logging → logging}/formatters/themes.py +0 -0
- /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
- /flock/{core/mcp → mcp}/util/__init__.py +0 -0
- {flock_core-0.4.542.dist-info → flock_core-0.5.0.dist-info}/WHEEL +0 -0
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
"""Defines granular Temporal activities for executing a single agent
|
|
2
|
-
and determining the next agent in a Flock workflow.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from collections.abc import Callable
|
|
6
|
-
|
|
7
|
-
from opentelemetry import trace
|
|
8
|
-
from temporalio import activity
|
|
9
|
-
|
|
10
|
-
# Third-party imports only within activity functions if needed, or pass context
|
|
11
|
-
# For core flock types, import directly
|
|
12
|
-
from flock.core.context.context import FlockContext
|
|
13
|
-
from flock.core.context.context_vars import (
|
|
14
|
-
FLOCK_MODEL,
|
|
15
|
-
FLOCK_USE_PRODUCTION_TOOLS,
|
|
16
|
-
)
|
|
17
|
-
from flock.core.flock_agent import FlockAgent # Import concrete class if needed
|
|
18
|
-
from flock.core.flock_registry import get_registry
|
|
19
|
-
from flock.core.flock_router import HandOffRequest
|
|
20
|
-
from flock.core.logging.logging import get_logger
|
|
21
|
-
from flock.core.util.input_resolver import resolve_inputs
|
|
22
|
-
|
|
23
|
-
logger = get_logger("agent_activity") # Using a distinct logger category
|
|
24
|
-
tracer = trace.get_tracer(__name__)
|
|
25
|
-
registry = get_registry() # Get registry instance once
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@activity.defn
|
|
29
|
-
async def execute_single_agent(agent_name: str, context: FlockContext) -> dict:
|
|
30
|
-
"""Executes a single specified agent and returns its result.
|
|
31
|
-
|
|
32
|
-
Args:
|
|
33
|
-
agent_name: The name of the agent to execute.
|
|
34
|
-
context: The current FlockContext (passed from the workflow).
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
The raw result dictionary from the agent's execution.
|
|
38
|
-
|
|
39
|
-
Raises:
|
|
40
|
-
ValueError: If the agent is not found in the registry.
|
|
41
|
-
Exception: Propagates exceptions from agent execution for Temporal retries.
|
|
42
|
-
"""
|
|
43
|
-
with tracer.start_as_current_span("execute_single_agent") as span:
|
|
44
|
-
span.set_attribute("agent.name", agent_name)
|
|
45
|
-
logger.info("Executing single agent", agent=agent_name)
|
|
46
|
-
|
|
47
|
-
agent = registry.get_agent(agent_name)
|
|
48
|
-
if not agent:
|
|
49
|
-
logger.error("Agent not found in registry", agent=agent_name)
|
|
50
|
-
# Raise error for Temporal to potentially retry/fail the activity
|
|
51
|
-
raise ValueError(f"Agent '{agent_name}' not found in registry.")
|
|
52
|
-
|
|
53
|
-
# Set agent's context reference (transient, for this execution)
|
|
54
|
-
agent.context = context
|
|
55
|
-
|
|
56
|
-
# Ensure model is set (using context value if needed)
|
|
57
|
-
# Consider if this should be done once when agent is added or workflow starts
|
|
58
|
-
if agent.model is None:
|
|
59
|
-
agent_model = context.get_variable(FLOCK_MODEL)
|
|
60
|
-
if agent_model:
|
|
61
|
-
agent.set_model(agent_model)
|
|
62
|
-
logger.debug(
|
|
63
|
-
f"Set model for agent '{agent_name}' from context: {agent_model}"
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
# Resolve agent-specific callables if necessary
|
|
67
|
-
# This might be better handled in the workflow before the loop starts
|
|
68
|
-
# or when agents are initially loaded. Assuming it's handled elsewhere for now.
|
|
69
|
-
# agent.resolve_callables(context=context)
|
|
70
|
-
|
|
71
|
-
# Resolve inputs for this specific agent run
|
|
72
|
-
previous_agent_name = (
|
|
73
|
-
context.get_last_agent_name()
|
|
74
|
-
) # Relies on context method
|
|
75
|
-
logger.debug(
|
|
76
|
-
f"Resolving inputs for {agent_name} with previous agent {previous_agent_name}"
|
|
77
|
-
)
|
|
78
|
-
agent_inputs = resolve_inputs(agent.input, context, previous_agent_name)
|
|
79
|
-
span.add_event(
|
|
80
|
-
"resolved inputs", attributes={"inputs": str(agent_inputs)}
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
try:
|
|
84
|
-
use_prod_tools = bool(
|
|
85
|
-
context.get_variable(FLOCK_USE_PRODUCTION_TOOLS, False)
|
|
86
|
-
)
|
|
87
|
-
span.set_attribute(
|
|
88
|
-
"tools.selection",
|
|
89
|
-
"production" if use_prod_tools else "dev",
|
|
90
|
-
)
|
|
91
|
-
# Execute just this agent
|
|
92
|
-
result = await agent.run_async(
|
|
93
|
-
agent_inputs, use_production_tools=use_prod_tools
|
|
94
|
-
)
|
|
95
|
-
# Avoid logging potentially large results directly to span attributes
|
|
96
|
-
result_str = str(result)
|
|
97
|
-
span.set_attribute("result.type", type(result).__name__)
|
|
98
|
-
span.set_attribute(
|
|
99
|
-
"result.preview",
|
|
100
|
-
result_str[:500] + ("..." if len(result_str) > 500 else ""),
|
|
101
|
-
)
|
|
102
|
-
logger.info("Single agent execution completed", agent=agent_name)
|
|
103
|
-
return result
|
|
104
|
-
except Exception as e:
|
|
105
|
-
logger.error(
|
|
106
|
-
"Single agent execution failed",
|
|
107
|
-
agent=agent_name,
|
|
108
|
-
error=str(e),
|
|
109
|
-
exc_info=True,
|
|
110
|
-
)
|
|
111
|
-
span.record_exception(e)
|
|
112
|
-
# Re-raise the exception for Temporal to handle based on retry policy
|
|
113
|
-
raise
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
@activity.defn
|
|
117
|
-
async def determine_next_agent(
|
|
118
|
-
current_agent_name: str, result: dict, context: FlockContext
|
|
119
|
-
) -> dict | None:
|
|
120
|
-
"""Determines the next agent using the current agent's handoff router.
|
|
121
|
-
|
|
122
|
-
Args:
|
|
123
|
-
current_agent_name: The name of the agent that just ran.
|
|
124
|
-
result: The result produced by the current agent.
|
|
125
|
-
context: The current FlockContext.
|
|
126
|
-
|
|
127
|
-
Returns:
|
|
128
|
-
A dictionary representing the HandOffRequest (serialized via model_dump),
|
|
129
|
-
or None if no handoff occurs or router doesn't specify a next agent.
|
|
130
|
-
|
|
131
|
-
Raises:
|
|
132
|
-
ValueError: If the current agent cannot be found.
|
|
133
|
-
Exception: Propagates exceptions from router execution for Temporal retries.
|
|
134
|
-
"""
|
|
135
|
-
with tracer.start_as_current_span("determine_next_agent") as span:
|
|
136
|
-
span.set_attribute("agent.name", current_agent_name)
|
|
137
|
-
logger.info("Determining next agent after", agent=current_agent_name)
|
|
138
|
-
|
|
139
|
-
agent = registry.get_agent(current_agent_name)
|
|
140
|
-
if not agent:
|
|
141
|
-
logger.error(
|
|
142
|
-
"Agent not found for routing", agent=current_agent_name
|
|
143
|
-
)
|
|
144
|
-
raise ValueError(
|
|
145
|
-
f"Agent '{current_agent_name}' not found for routing."
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
if not agent.handoff_router:
|
|
149
|
-
logger.info(
|
|
150
|
-
"No handoff router defined for agent", agent=current_agent_name
|
|
151
|
-
)
|
|
152
|
-
span.add_event("no_router")
|
|
153
|
-
return None # Indicate no handoff
|
|
154
|
-
|
|
155
|
-
logger.debug(
|
|
156
|
-
f"Using router {agent.handoff_router.__class__.__name__}",
|
|
157
|
-
agent=agent.name,
|
|
158
|
-
)
|
|
159
|
-
try:
|
|
160
|
-
# Execute the routing logic
|
|
161
|
-
handoff_data: (
|
|
162
|
-
HandOffRequest | Callable
|
|
163
|
-
) = await agent.handoff_router.route(agent, result, context)
|
|
164
|
-
|
|
165
|
-
# Handle callable handoff functions - This is complex in distributed systems.
|
|
166
|
-
# Consider if this pattern should be supported or if routing should always
|
|
167
|
-
# return serializable data directly. Executing arbitrary code from context
|
|
168
|
-
# within an activity can have side effects and security implications.
|
|
169
|
-
# Assuming for now it MUST return HandOffRequest or structure convertible to it.
|
|
170
|
-
if callable(handoff_data):
|
|
171
|
-
logger.warning(
|
|
172
|
-
"Callable handoff detected - executing function.",
|
|
173
|
-
agent=agent.name,
|
|
174
|
-
)
|
|
175
|
-
# Ensure context is available if the callable needs it
|
|
176
|
-
try:
|
|
177
|
-
handoff_data = handoff_data(
|
|
178
|
-
context, result
|
|
179
|
-
) # Potential side effects
|
|
180
|
-
if not isinstance(handoff_data, HandOffRequest):
|
|
181
|
-
logger.error(
|
|
182
|
-
"Handoff function did not return a HandOffRequest object.",
|
|
183
|
-
agent=agent.name,
|
|
184
|
-
)
|
|
185
|
-
raise TypeError(
|
|
186
|
-
"Handoff function must return a HandOffRequest object."
|
|
187
|
-
)
|
|
188
|
-
except Exception as e:
|
|
189
|
-
logger.error(
|
|
190
|
-
"Handoff function execution failed",
|
|
191
|
-
agent=agent.name,
|
|
192
|
-
error=str(e),
|
|
193
|
-
exc_info=True,
|
|
194
|
-
)
|
|
195
|
-
span.record_exception(e)
|
|
196
|
-
raise # Propagate error
|
|
197
|
-
|
|
198
|
-
# Ensure we have a HandOffRequest object after potentially calling function
|
|
199
|
-
if not isinstance(handoff_data, HandOffRequest):
|
|
200
|
-
logger.error(
|
|
201
|
-
"Router returned unexpected type",
|
|
202
|
-
type=type(handoff_data).__name__,
|
|
203
|
-
agent=agent.name,
|
|
204
|
-
)
|
|
205
|
-
raise TypeError(
|
|
206
|
-
f"Router for agent '{agent.name}' did not return a HandOffRequest object."
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
# Ensure agent instance is converted to name for serialization across boundaries
|
|
210
|
-
if isinstance(handoff_data.next_agent, FlockAgent):
|
|
211
|
-
handoff_data.next_agent = handoff_data.next_agent.name
|
|
212
|
-
|
|
213
|
-
# If router logic determines no further agent, return None
|
|
214
|
-
if not handoff_data.next_agent:
|
|
215
|
-
logger.info("Router determined no next agent", agent=agent.name)
|
|
216
|
-
span.add_event("no_next_agent_from_router")
|
|
217
|
-
return None
|
|
218
|
-
|
|
219
|
-
logger.info(
|
|
220
|
-
"Handoff determined",
|
|
221
|
-
next_agent=handoff_data.next_agent,
|
|
222
|
-
agent=agent.name,
|
|
223
|
-
)
|
|
224
|
-
span.set_attribute("next_agent", handoff_data.next_agent)
|
|
225
|
-
# Return the serializable HandOffRequest data using Pydantic's export method
|
|
226
|
-
return handoff_data.model_dump(
|
|
227
|
-
mode="json"
|
|
228
|
-
) # Ensure JSON-serializable
|
|
229
|
-
|
|
230
|
-
except Exception as e:
|
|
231
|
-
# Catch potential errors during routing execution
|
|
232
|
-
logger.error(
|
|
233
|
-
"Router execution failed",
|
|
234
|
-
agent=agent.name,
|
|
235
|
-
error=str(e),
|
|
236
|
-
exc_info=True,
|
|
237
|
-
)
|
|
238
|
-
span.record_exception(e)
|
|
239
|
-
# Let Temporal handle the activity failure based on retry policy
|
|
240
|
-
raise
|
flock/workflow/flock_workflow.py
DELETED
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
from datetime import timedelta
|
|
2
|
-
from typing import Any
|
|
3
|
-
|
|
4
|
-
from temporalio import workflow
|
|
5
|
-
|
|
6
|
-
# Import activities from the new file
|
|
7
|
-
with workflow.unsafe.imports_passed_through():
|
|
8
|
-
from flock.core.context.context import AgentDefinition, FlockContext
|
|
9
|
-
from flock.core.context.context_vars import FLOCK_CURRENT_AGENT
|
|
10
|
-
from flock.core.flock_router import HandOffRequest
|
|
11
|
-
from flock.core.logging.logging import get_logger
|
|
12
|
-
from flock.workflow.agent_execution_activity import (
|
|
13
|
-
determine_next_agent,
|
|
14
|
-
execute_single_agent,
|
|
15
|
-
)
|
|
16
|
-
from flock.workflow.temporal_config import (
|
|
17
|
-
TemporalActivityConfig,
|
|
18
|
-
TemporalRetryPolicyConfig,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
logger = get_logger("workflow")
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@workflow.defn
|
|
26
|
-
class FlockWorkflow:
|
|
27
|
-
# No need for __init__ storing context anymore if passed to run
|
|
28
|
-
|
|
29
|
-
@workflow.run
|
|
30
|
-
async def run(self, workflow_args: dict[str, Any]) -> dict:
|
|
31
|
-
# --- Workflow Initialization ---
|
|
32
|
-
# Arguments are packed into a single dictionary
|
|
33
|
-
context_dict = workflow_args["context_dict"]
|
|
34
|
-
default_retry_config_dict = workflow_args["default_retry_config_dict"]
|
|
35
|
-
|
|
36
|
-
# Deserialize context and default retry config
|
|
37
|
-
context = FlockContext.from_dict(context_dict)
|
|
38
|
-
default_retry_config = TemporalRetryPolicyConfig.model_validate(
|
|
39
|
-
default_retry_config_dict
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
context.workflow_id = workflow.info().workflow_id
|
|
43
|
-
context.workflow_timestamp = workflow.info().start_time.strftime(
|
|
44
|
-
"%Y-%m-%d %H:%M:%S"
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
current_agent_name = context.get_variable(FLOCK_CURRENT_AGENT)
|
|
48
|
-
final_result = None
|
|
49
|
-
previous_agent_name = (
|
|
50
|
-
None # Keep track of the agent that called the current one
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
logger.info(
|
|
54
|
-
"Starting workflow execution",
|
|
55
|
-
workflow_id=context.workflow_id,
|
|
56
|
-
start_time=context.workflow_timestamp,
|
|
57
|
-
initial_agent=current_agent_name,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
try:
|
|
61
|
-
while current_agent_name:
|
|
62
|
-
logger.info(
|
|
63
|
-
"Executing agent activity", agent=current_agent_name
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
# --- Determine Activity Settings ---
|
|
67
|
-
agent_def: AgentDefinition | None = (
|
|
68
|
-
context.get_agent_definition(current_agent_name)
|
|
69
|
-
)
|
|
70
|
-
agent_activity_config: TemporalActivityConfig | None = None
|
|
71
|
-
final_retry_config = (
|
|
72
|
-
default_retry_config # Start with the workflow default
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
if agent_def and agent_def.agent_data.get(
|
|
76
|
-
"temporal_activity_config"
|
|
77
|
-
):
|
|
78
|
-
try:
|
|
79
|
-
agent_activity_config = (
|
|
80
|
-
TemporalActivityConfig.model_validate(
|
|
81
|
-
agent_def.agent_data["temporal_activity_config"]
|
|
82
|
-
)
|
|
83
|
-
)
|
|
84
|
-
logger.debug(
|
|
85
|
-
f"Loaded agent-specific temporal config for {current_agent_name}"
|
|
86
|
-
)
|
|
87
|
-
except Exception as e:
|
|
88
|
-
logger.warn(
|
|
89
|
-
f"Failed to validate agent temporal config for {current_agent_name}: {e}. Using defaults."
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
# Layering logic: Agent config overrides workflow default config
|
|
93
|
-
activity_task_queue = (
|
|
94
|
-
workflow.info().task_queue
|
|
95
|
-
) # Default to workflow task queue
|
|
96
|
-
activity_timeout = timedelta(
|
|
97
|
-
minutes=5
|
|
98
|
-
) # Fallback default timeout
|
|
99
|
-
|
|
100
|
-
if agent_activity_config:
|
|
101
|
-
activity_task_queue = (
|
|
102
|
-
agent_activity_config.task_queue or activity_task_queue
|
|
103
|
-
)
|
|
104
|
-
activity_timeout = (
|
|
105
|
-
agent_activity_config.start_to_close_timeout
|
|
106
|
-
or activity_timeout
|
|
107
|
-
)
|
|
108
|
-
if agent_activity_config.retry_policy:
|
|
109
|
-
final_retry_config = agent_activity_config.retry_policy
|
|
110
|
-
|
|
111
|
-
# Convert config to actual Temporal object
|
|
112
|
-
final_retry_policy = final_retry_config.to_temporalio_policy()
|
|
113
|
-
|
|
114
|
-
logger.debug(
|
|
115
|
-
f"Final activity settings for {current_agent_name}: "
|
|
116
|
-
f"queue='{activity_task_queue}', timeout={activity_timeout}, "
|
|
117
|
-
f"retries={final_retry_policy.maximum_attempts}"
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
# --- Execute the current agent activity ---
|
|
121
|
-
agent_result = await workflow.execute_activity(
|
|
122
|
-
execute_single_agent,
|
|
123
|
-
args=[current_agent_name, context],
|
|
124
|
-
task_queue=activity_task_queue, # Use determined task queue
|
|
125
|
-
start_to_close_timeout=activity_timeout, # Use determined timeout
|
|
126
|
-
retry_policy=final_retry_policy, # Use determined retry policy
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
# Record the execution in the context history
|
|
130
|
-
# Note: The 'called_from' is the agent *before* this one
|
|
131
|
-
context.record(
|
|
132
|
-
agent_name=current_agent_name,
|
|
133
|
-
data=agent_result,
|
|
134
|
-
timestamp=workflow.now().isoformat(), # Use deterministic workflow time
|
|
135
|
-
hand_off=None, # Will be updated if handoff occurs
|
|
136
|
-
called_from=previous_agent_name, # Pass the correct previous agent
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
final_result = agent_result # Store the result of the last successful agent
|
|
140
|
-
|
|
141
|
-
logger.info(
|
|
142
|
-
"Determining next agent activity",
|
|
143
|
-
current_agent=current_agent_name,
|
|
144
|
-
)
|
|
145
|
-
# --- Determine the next agent activity (using workflow defaults for now) ---
|
|
146
|
-
# We could apply similar config logic to determine_next_agent if needed
|
|
147
|
-
handoff_data_dict = await workflow.execute_activity(
|
|
148
|
-
determine_next_agent,
|
|
149
|
-
args=[current_agent_name, agent_result, context],
|
|
150
|
-
# Using sensible defaults, but could be configured via workflow_config?
|
|
151
|
-
start_to_close_timeout=timedelta(minutes=1),
|
|
152
|
-
retry_policy=default_retry_config.to_temporalio_policy(), # Use default retry
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
# Update previous agent name for the next loop iteration
|
|
156
|
-
previous_agent_name = current_agent_name
|
|
157
|
-
|
|
158
|
-
if handoff_data_dict:
|
|
159
|
-
logger.debug(
|
|
160
|
-
"Handoff data received", data=handoff_data_dict
|
|
161
|
-
)
|
|
162
|
-
# Deserialize handoff data back into Pydantic model for easier access
|
|
163
|
-
handoff_request = HandOffRequest.model_validate(
|
|
164
|
-
handoff_data_dict
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
# Update context based on handoff overrides
|
|
168
|
-
if handoff_request.override_context:
|
|
169
|
-
context.state.update(handoff_request.override_context)
|
|
170
|
-
logger.info("Context updated based on handoff override")
|
|
171
|
-
|
|
172
|
-
# Update the last record's handoff information
|
|
173
|
-
if context.history:
|
|
174
|
-
context.history[-1].hand_off = handoff_data_dict
|
|
175
|
-
|
|
176
|
-
# Set the next agent
|
|
177
|
-
current_agent_name = handoff_request.next_agent
|
|
178
|
-
if current_agent_name:
|
|
179
|
-
context.set_variable(
|
|
180
|
-
FLOCK_CURRENT_AGENT, current_agent_name
|
|
181
|
-
)
|
|
182
|
-
logger.info("Next agent set", agent=current_agent_name)
|
|
183
|
-
else:
|
|
184
|
-
logger.info(
|
|
185
|
-
"Handoff requested termination (no next agent)"
|
|
186
|
-
)
|
|
187
|
-
break # Exit loop if router explicitly returned no next agent
|
|
188
|
-
|
|
189
|
-
else:
|
|
190
|
-
# No handoff data returned (no router or router returned None)
|
|
191
|
-
logger.info("No handoff occurred, workflow terminating.")
|
|
192
|
-
current_agent_name = None # End the loop
|
|
193
|
-
|
|
194
|
-
# --- Workflow Completion ---
|
|
195
|
-
logger.success(
|
|
196
|
-
"Workflow completed successfully",
|
|
197
|
-
final_agent=previous_agent_name,
|
|
198
|
-
)
|
|
199
|
-
context.set_variable(
|
|
200
|
-
"flock.result",
|
|
201
|
-
{
|
|
202
|
-
"result": final_result, # Return the last agent's result
|
|
203
|
-
"success": True,
|
|
204
|
-
},
|
|
205
|
-
)
|
|
206
|
-
return final_result # Return the actual result of the last agent
|
|
207
|
-
|
|
208
|
-
except Exception as e:
|
|
209
|
-
# Catch exceptions from activities (e.g., after retries fail)
|
|
210
|
-
# or workflow logic errors
|
|
211
|
-
logger.exception("Workflow execution failed", error=str(e))
|
|
212
|
-
context.set_variable(
|
|
213
|
-
"flock.result",
|
|
214
|
-
{
|
|
215
|
-
"result": f"Workflow failed: {e}",
|
|
216
|
-
"success": False,
|
|
217
|
-
},
|
|
218
|
-
)
|
|
219
|
-
# It's often better to let Temporal record the failure status
|
|
220
|
-
# by re-raising the exception rather than returning a custom error dict.
|
|
221
|
-
# However, returning the context might be useful for debugging.
|
|
222
|
-
# Consider re-raising: raise
|
|
223
|
-
return context.model_dump(
|
|
224
|
-
mode="json"
|
|
225
|
-
) # Return context state on failure
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# src/flock/config/temporal_config.py
|
|
2
|
-
|
|
3
|
-
"""Pydantic models for configuring Temporal execution settings."""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from datetime import timedelta
|
|
8
|
-
from typing import TYPE_CHECKING
|
|
9
|
-
|
|
10
|
-
# Conditionally import for type hinting only
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from temporalio.common import RetryPolicy
|
|
13
|
-
|
|
14
|
-
# Note: Importing temporalio types directly into config models can complicate serialization
|
|
15
|
-
# if these models are meant to be purely data containers (e.g., for YAML/JSON).
|
|
16
|
-
# We define the structure and provide a helper method to convert to the actual Temporal object.
|
|
17
|
-
# Be careful if using workflow/activity decorators directly on methods within these config models.
|
|
18
|
-
from pydantic import BaseModel, Field
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class TemporalRetryPolicyConfig(BaseModel):
|
|
22
|
-
"""Configuration parameters for Temporal Retry Policies."""
|
|
23
|
-
|
|
24
|
-
initial_interval: timedelta = Field(
|
|
25
|
-
default=timedelta(seconds=1),
|
|
26
|
-
description="Initial delay before the first retry.",
|
|
27
|
-
)
|
|
28
|
-
backoff_coefficient: float = Field(
|
|
29
|
-
default=2.0, description="Multiplier for the delay between retries."
|
|
30
|
-
)
|
|
31
|
-
maximum_interval: timedelta | None = Field(
|
|
32
|
-
default=timedelta(seconds=100),
|
|
33
|
-
description="Maximum delay between retries.",
|
|
34
|
-
)
|
|
35
|
-
maximum_attempts: int = Field(
|
|
36
|
-
default=3,
|
|
37
|
-
description="Maximum number of retry attempts (0 means no retries after first failure).",
|
|
38
|
-
)
|
|
39
|
-
non_retryable_error_types: list[str] = Field(
|
|
40
|
-
default_factory=list,
|
|
41
|
-
description="List of error type names (strings) that should not be retried.",
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
# Helper to convert to actual Temporalio object when needed (e.g., in workflow/executor)
|
|
45
|
-
def to_temporalio_policy(self) -> RetryPolicy:
|
|
46
|
-
# Import locally to avoid making temporalio a hard dependency of the config module itself
|
|
47
|
-
# The type hint RetryPolicy is now available due to TYPE_CHECKING block
|
|
48
|
-
from temporalio.common import RetryPolicy
|
|
49
|
-
|
|
50
|
-
return RetryPolicy(
|
|
51
|
-
initial_interval=self.initial_interval,
|
|
52
|
-
backoff_coefficient=self.backoff_coefficient,
|
|
53
|
-
maximum_interval=self.maximum_interval,
|
|
54
|
-
maximum_attempts=self.maximum_attempts,
|
|
55
|
-
non_retryable_error_types=self.non_retryable_error_types,
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class TemporalWorkflowConfig(BaseModel):
|
|
60
|
-
"""Configuration specific to Temporal Workflow Execution for a Flock."""
|
|
61
|
-
|
|
62
|
-
task_queue: str = Field(
|
|
63
|
-
default="flock-queue",
|
|
64
|
-
description="Default task queue for the workflow execution.",
|
|
65
|
-
)
|
|
66
|
-
workflow_execution_timeout: timedelta | None = Field(
|
|
67
|
-
default=None, # Default to no timeout (Temporal server default)
|
|
68
|
-
description="Total time limit for the workflow execution.",
|
|
69
|
-
)
|
|
70
|
-
workflow_run_timeout: timedelta | None = Field(
|
|
71
|
-
default=None, # Default to no timeout (Temporal server default)
|
|
72
|
-
description="Time limit for a single workflow run attempt.",
|
|
73
|
-
)
|
|
74
|
-
# Default retry policy for activities if not specified per-agent
|
|
75
|
-
default_activity_retry_policy: TemporalRetryPolicyConfig = Field(
|
|
76
|
-
default_factory=TemporalRetryPolicyConfig,
|
|
77
|
-
description="Default retry policy applied to activities if not overridden by the agent.",
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
class TemporalActivityConfig(BaseModel):
|
|
82
|
-
"""Configuration specific to Temporal Activity Execution (per Agent)."""
|
|
83
|
-
|
|
84
|
-
task_queue: str | None = Field(
|
|
85
|
-
default=None,
|
|
86
|
-
description="Specific task queue for this agent's activity execution (overrides workflow default).",
|
|
87
|
-
)
|
|
88
|
-
start_to_close_timeout: timedelta | None = Field(
|
|
89
|
-
default=timedelta(minutes=5), # Default to 5 minutes
|
|
90
|
-
description="Time limit for a single activity attempt.",
|
|
91
|
-
)
|
|
92
|
-
retry_policy: TemporalRetryPolicyConfig | None = Field(
|
|
93
|
-
default=None,
|
|
94
|
-
description="Specific retry policy for this activity (overrides workflow default).",
|
|
95
|
-
)
|
|
96
|
-
# Other timeouts like schedule_to_start, heartbeat_timeout could be added here if needed
|
flock/workflow/temporal_setup.py
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import uuid
|
|
2
|
-
|
|
3
|
-
from temporalio.client import Client
|
|
4
|
-
from temporalio.worker import Worker
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
async def create_temporal_client() -> Client:
|
|
8
|
-
# Consider making the address configurable
|
|
9
|
-
client = await Client.connect("localhost:7233")
|
|
10
|
-
return client
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
async def setup_worker(
|
|
14
|
-
client: Client, task_queue: str, workflow: type, activities: list
|
|
15
|
-
) -> Worker:
|
|
16
|
-
"""Creates and configures a worker instance, but does not run it.
|
|
17
|
-
|
|
18
|
-
Args:
|
|
19
|
-
client: The Temporal client to associate with the worker.
|
|
20
|
-
task_queue: The task queue the worker should listen on.
|
|
21
|
-
workflow: The workflow class definition.
|
|
22
|
-
activities: A list of activity functions.
|
|
23
|
-
|
|
24
|
-
Returns:
|
|
25
|
-
A configured Worker instance.
|
|
26
|
-
"""
|
|
27
|
-
# Creates and configures the worker instance
|
|
28
|
-
worker = Worker(
|
|
29
|
-
client,
|
|
30
|
-
task_queue=task_queue,
|
|
31
|
-
workflows=[workflow],
|
|
32
|
-
activities=activities,
|
|
33
|
-
)
|
|
34
|
-
return worker # Return the configured worker instance
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
async def run_worker(client: Client, task_queue: str, workflows, activities):
|
|
38
|
-
worker = Worker(
|
|
39
|
-
client,
|
|
40
|
-
task_queue=task_queue,
|
|
41
|
-
workflows=workflows,
|
|
42
|
-
activities=activities,
|
|
43
|
-
)
|
|
44
|
-
await worker.run()
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
async def run_activity(client: Client, name: str, func, param):
|
|
48
|
-
run_id = f"{name}_{uuid.uuid4().hex[:4]}"
|
|
49
|
-
|
|
50
|
-
try:
|
|
51
|
-
result = await client.execute_activity(
|
|
52
|
-
func,
|
|
53
|
-
param,
|
|
54
|
-
id=run_id,
|
|
55
|
-
task_queue="flock-queue",
|
|
56
|
-
start_to_close_timeout=300, # e.g., 5 minutes
|
|
57
|
-
)
|
|
58
|
-
return result
|
|
59
|
-
except Exception:
|
|
60
|
-
raise
|