flock-core 0.4.543__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of flock-core might be problematic. Click here for more details.

Files changed (501) hide show
  1. flock/__init__.py +12 -217
  2. flock/agent.py +1079 -0
  3. flock/api/themes.py +71 -0
  4. flock/artifacts.py +86 -0
  5. flock/cli.py +147 -0
  6. flock/components.py +189 -0
  7. flock/dashboard/__init__.py +30 -0
  8. flock/dashboard/collector.py +559 -0
  9. flock/dashboard/events.py +188 -0
  10. flock/dashboard/graph_builder.py +563 -0
  11. flock/dashboard/launcher.py +235 -0
  12. flock/dashboard/models/graph.py +156 -0
  13. flock/dashboard/service.py +991 -0
  14. flock/dashboard/static_v2/assets/index-DFRnI_mt.js +111 -0
  15. flock/dashboard/static_v2/assets/index-fPLNdmp1.css +1 -0
  16. flock/dashboard/static_v2/index.html +13 -0
  17. flock/dashboard/websocket.py +246 -0
  18. flock/engines/__init__.py +6 -0
  19. flock/engines/dspy_engine.py +932 -0
  20. flock/examples.py +131 -0
  21. flock/frontend/README.md +778 -0
  22. flock/frontend/docs/DESIGN_SYSTEM.md +1980 -0
  23. flock/frontend/index.html +12 -0
  24. flock/frontend/package-lock.json +4337 -0
  25. flock/frontend/package.json +48 -0
  26. flock/frontend/src/App.tsx +139 -0
  27. flock/frontend/src/__tests__/integration/graph-snapshot.test.tsx +647 -0
  28. flock/frontend/src/__tests__/integration/indexeddb-persistence.test.tsx +699 -0
  29. flock/frontend/src/components/common/BuildInfo.tsx +39 -0
  30. flock/frontend/src/components/common/EmptyState.module.css +115 -0
  31. flock/frontend/src/components/common/EmptyState.tsx +128 -0
  32. flock/frontend/src/components/common/ErrorBoundary.module.css +169 -0
  33. flock/frontend/src/components/common/ErrorBoundary.tsx +118 -0
  34. flock/frontend/src/components/common/KeyboardShortcutsDialog.css +251 -0
  35. flock/frontend/src/components/common/KeyboardShortcutsDialog.tsx +151 -0
  36. flock/frontend/src/components/common/LoadingSpinner.module.css +97 -0
  37. flock/frontend/src/components/common/LoadingSpinner.tsx +29 -0
  38. flock/frontend/src/components/controls/PublishControl.css +547 -0
  39. flock/frontend/src/components/controls/PublishControl.test.tsx +543 -0
  40. flock/frontend/src/components/controls/PublishControl.tsx +432 -0
  41. flock/frontend/src/components/details/DetailWindowContainer.tsx +58 -0
  42. flock/frontend/src/components/details/LiveOutputTab.test.tsx +792 -0
  43. flock/frontend/src/components/details/LiveOutputTab.tsx +220 -0
  44. flock/frontend/src/components/details/MessageDetailWindow.tsx +439 -0
  45. flock/frontend/src/components/details/MessageHistoryTab.tsx +374 -0
  46. flock/frontend/src/components/details/NodeDetailWindow.test.tsx +501 -0
  47. flock/frontend/src/components/details/NodeDetailWindow.tsx +218 -0
  48. flock/frontend/src/components/details/RunStatusTab.tsx +348 -0
  49. flock/frontend/src/components/details/tabs.test.tsx +1015 -0
  50. flock/frontend/src/components/filters/ArtifactTypeFilter.tsx +21 -0
  51. flock/frontend/src/components/filters/CorrelationIDFilter.module.css +102 -0
  52. flock/frontend/src/components/filters/CorrelationIDFilter.test.tsx +197 -0
  53. flock/frontend/src/components/filters/CorrelationIDFilter.tsx +121 -0
  54. flock/frontend/src/components/filters/FilterFlyout.module.css +104 -0
  55. flock/frontend/src/components/filters/FilterFlyout.tsx +80 -0
  56. flock/frontend/src/components/filters/FilterPills.module.css +220 -0
  57. flock/frontend/src/components/filters/FilterPills.test.tsx +189 -0
  58. flock/frontend/src/components/filters/FilterPills.tsx +143 -0
  59. flock/frontend/src/components/filters/ProducerFilter.tsx +21 -0
  60. flock/frontend/src/components/filters/SavedFiltersControl.module.css +60 -0
  61. flock/frontend/src/components/filters/SavedFiltersControl.test.tsx +158 -0
  62. flock/frontend/src/components/filters/SavedFiltersControl.tsx +159 -0
  63. flock/frontend/src/components/filters/TagFilter.tsx +21 -0
  64. flock/frontend/src/components/filters/TimeRangeFilter.module.css +115 -0
  65. flock/frontend/src/components/filters/TimeRangeFilter.test.tsx +154 -0
  66. flock/frontend/src/components/filters/TimeRangeFilter.tsx +110 -0
  67. flock/frontend/src/components/filters/VisibilityFilter.tsx +21 -0
  68. flock/frontend/src/components/graph/AgentNode.test.tsx +77 -0
  69. flock/frontend/src/components/graph/AgentNode.tsx +324 -0
  70. flock/frontend/src/components/graph/GraphCanvas.tsx +613 -0
  71. flock/frontend/src/components/graph/MessageFlowEdge.tsx +128 -0
  72. flock/frontend/src/components/graph/MessageNode.test.tsx +64 -0
  73. flock/frontend/src/components/graph/MessageNode.tsx +129 -0
  74. flock/frontend/src/components/graph/MiniMap.tsx +47 -0
  75. flock/frontend/src/components/graph/TransformEdge.tsx +123 -0
  76. flock/frontend/src/components/layout/DashboardLayout.css +420 -0
  77. flock/frontend/src/components/layout/DashboardLayout.tsx +287 -0
  78. flock/frontend/src/components/layout/Header.module.css +88 -0
  79. flock/frontend/src/components/layout/Header.tsx +52 -0
  80. flock/frontend/src/components/modules/HistoricalArtifactsModule.module.css +288 -0
  81. flock/frontend/src/components/modules/HistoricalArtifactsModule.tsx +450 -0
  82. flock/frontend/src/components/modules/HistoricalArtifactsModuleWrapper.tsx +13 -0
  83. flock/frontend/src/components/modules/JsonAttributeRenderer.tsx +140 -0
  84. flock/frontend/src/components/modules/ModuleRegistry.test.ts +333 -0
  85. flock/frontend/src/components/modules/ModuleRegistry.ts +93 -0
  86. flock/frontend/src/components/modules/ModuleWindow.tsx +223 -0
  87. flock/frontend/src/components/modules/TraceModuleJaeger.tsx +1971 -0
  88. flock/frontend/src/components/modules/TraceModuleJaegerWrapper.tsx +13 -0
  89. flock/frontend/src/components/modules/registerModules.ts +29 -0
  90. flock/frontend/src/components/settings/AdvancedSettings.tsx +175 -0
  91. flock/frontend/src/components/settings/AppearanceSettings.tsx +185 -0
  92. flock/frontend/src/components/settings/GraphSettings.tsx +110 -0
  93. flock/frontend/src/components/settings/MultiSelect.tsx +235 -0
  94. flock/frontend/src/components/settings/SettingsPanel.css +327 -0
  95. flock/frontend/src/components/settings/SettingsPanel.tsx +131 -0
  96. flock/frontend/src/components/settings/ThemeSelector.tsx +298 -0
  97. flock/frontend/src/components/settings/TracingSettings.tsx +404 -0
  98. flock/frontend/src/hooks/useKeyboardShortcuts.ts +148 -0
  99. flock/frontend/src/hooks/useModulePersistence.test.ts +442 -0
  100. flock/frontend/src/hooks/useModulePersistence.ts +154 -0
  101. flock/frontend/src/hooks/useModules.ts +157 -0
  102. flock/frontend/src/hooks/usePersistence.ts +141 -0
  103. flock/frontend/src/main.tsx +13 -0
  104. flock/frontend/src/services/api.ts +337 -0
  105. flock/frontend/src/services/graphService.test.ts +330 -0
  106. flock/frontend/src/services/graphService.ts +75 -0
  107. flock/frontend/src/services/indexeddb.test.ts +793 -0
  108. flock/frontend/src/services/indexeddb.ts +848 -0
  109. flock/frontend/src/services/layout.test.ts +437 -0
  110. flock/frontend/src/services/layout.ts +357 -0
  111. flock/frontend/src/services/themeApplicator.ts +140 -0
  112. flock/frontend/src/services/themeService.ts +77 -0
  113. flock/frontend/src/services/websocket.ts +650 -0
  114. flock/frontend/src/store/filterStore.test.ts +250 -0
  115. flock/frontend/src/store/filterStore.ts +272 -0
  116. flock/frontend/src/store/graphStore.test.ts +570 -0
  117. flock/frontend/src/store/graphStore.ts +462 -0
  118. flock/frontend/src/store/moduleStore.test.ts +253 -0
  119. flock/frontend/src/store/moduleStore.ts +75 -0
  120. flock/frontend/src/store/settingsStore.ts +188 -0
  121. flock/frontend/src/store/streamStore.ts +68 -0
  122. flock/frontend/src/store/uiStore.test.ts +54 -0
  123. flock/frontend/src/store/uiStore.ts +122 -0
  124. flock/frontend/src/store/wsStore.ts +34 -0
  125. flock/frontend/src/styles/index.css +15 -0
  126. flock/frontend/src/styles/scrollbar.css +47 -0
  127. flock/frontend/src/styles/variables.css +488 -0
  128. flock/frontend/src/test/setup.ts +1 -0
  129. flock/frontend/src/types/filters.ts +47 -0
  130. flock/frontend/src/types/graph.ts +95 -0
  131. flock/frontend/src/types/modules.ts +10 -0
  132. flock/frontend/src/types/theme.ts +55 -0
  133. flock/frontend/src/utils/artifacts.ts +24 -0
  134. flock/frontend/src/utils/mockData.ts +98 -0
  135. flock/frontend/src/utils/performance.ts +16 -0
  136. flock/frontend/src/vite-env.d.ts +17 -0
  137. flock/frontend/tsconfig.json +27 -0
  138. flock/frontend/tsconfig.node.json +11 -0
  139. flock/frontend/vite.config.ts +25 -0
  140. flock/frontend/vitest.config.ts +11 -0
  141. flock/{core/util → helper}/cli_helper.py +9 -5
  142. flock/{core/logging → logging}/__init__.py +2 -3
  143. flock/logging/auto_trace.py +159 -0
  144. flock/{core/logging → logging}/formatters/enum_builder.py +3 -4
  145. flock/{core/logging → logging}/formatters/theme_builder.py +19 -44
  146. flock/{core/logging → logging}/formatters/themed_formatter.py +69 -107
  147. flock/{core/logging → logging}/logging.py +78 -61
  148. flock/{core/logging → logging}/telemetry.py +66 -26
  149. flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
  150. flock/logging/telemetry_exporter/duckdb_exporter.py +216 -0
  151. flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +13 -10
  152. flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
  153. flock/logging/trace_and_logged.py +304 -0
  154. flock/mcp/__init__.py +91 -0
  155. flock/{core/mcp/mcp_client.py → mcp/client.py} +131 -158
  156. flock/{core/mcp/mcp_config.py → mcp/config.py} +86 -132
  157. flock/mcp/manager.py +286 -0
  158. flock/mcp/servers/sse/__init__.py +1 -1
  159. flock/mcp/servers/sse/flock_sse_server.py +16 -58
  160. flock/mcp/servers/stdio/__init__.py +1 -1
  161. flock/mcp/servers/stdio/flock_stdio_server.py +13 -53
  162. flock/mcp/servers/streamable_http/flock_streamable_http_server.py +22 -67
  163. flock/mcp/servers/websockets/flock_websocket_server.py +12 -45
  164. flock/{core/mcp/flock_mcp_tool_base.py → mcp/tool.py} +24 -78
  165. flock/mcp/types/__init__.py +42 -0
  166. flock/{core/mcp → mcp}/types/callbacks.py +12 -15
  167. flock/{core/mcp → mcp}/types/factories.py +7 -6
  168. flock/{core/mcp → mcp}/types/handlers.py +13 -18
  169. flock/{core/mcp → mcp}/types/types.py +70 -74
  170. flock/{core/mcp → mcp}/util/helpers.py +3 -3
  171. flock/orchestrator.py +970 -0
  172. flock/registry.py +148 -0
  173. flock/runtime.py +262 -0
  174. flock/service.py +277 -0
  175. flock/store.py +1214 -0
  176. flock/subscription.py +111 -0
  177. flock/themes/andromeda.toml +1 -1
  178. flock/themes/apple-system-colors.toml +1 -1
  179. flock/themes/arcoiris.toml +1 -1
  180. flock/themes/atomonelight.toml +1 -1
  181. flock/themes/ayu copy.toml +1 -1
  182. flock/themes/ayu-light.toml +1 -1
  183. flock/themes/belafonte-day.toml +1 -1
  184. flock/themes/belafonte-night.toml +1 -1
  185. flock/themes/blulocodark.toml +1 -1
  186. flock/themes/breeze.toml +1 -1
  187. flock/themes/broadcast.toml +1 -1
  188. flock/themes/brogrammer.toml +1 -1
  189. flock/themes/builtin-dark.toml +1 -1
  190. flock/themes/builtin-pastel-dark.toml +1 -1
  191. flock/themes/catppuccin-latte.toml +1 -1
  192. flock/themes/catppuccin-macchiato.toml +1 -1
  193. flock/themes/catppuccin-mocha.toml +1 -1
  194. flock/themes/cga.toml +1 -1
  195. flock/themes/chalk.toml +1 -1
  196. flock/themes/ciapre.toml +1 -1
  197. flock/themes/coffee-theme.toml +1 -1
  198. flock/themes/cyberpunkscarletprotocol.toml +1 -1
  199. flock/themes/dark+.toml +1 -1
  200. flock/themes/darkermatrix.toml +1 -1
  201. flock/themes/darkmatrix.toml +2 -2
  202. flock/themes/darkside.toml +1 -1
  203. flock/themes/deep.toml +2 -2
  204. flock/themes/desert.toml +1 -1
  205. flock/themes/django.toml +1 -1
  206. flock/themes/djangosmooth.toml +1 -1
  207. flock/themes/doomone.toml +1 -1
  208. flock/themes/dotgov.toml +1 -1
  209. flock/themes/dracula+.toml +1 -1
  210. flock/themes/duckbones.toml +1 -1
  211. flock/themes/encom.toml +1 -1
  212. flock/themes/espresso.toml +1 -1
  213. flock/themes/everblush.toml +1 -1
  214. flock/themes/fairyfloss.toml +1 -1
  215. flock/themes/fideloper.toml +1 -1
  216. flock/themes/fishtank.toml +1 -1
  217. flock/themes/flexoki-light.toml +1 -1
  218. flock/themes/floraverse.toml +1 -1
  219. flock/themes/framer.toml +1 -1
  220. flock/themes/galizur.toml +1 -1
  221. flock/themes/github.toml +1 -1
  222. flock/themes/grass.toml +1 -1
  223. flock/themes/grey-green.toml +1 -1
  224. flock/themes/gruvboxlight.toml +1 -1
  225. flock/themes/guezwhoz.toml +1 -1
  226. flock/themes/harper.toml +1 -1
  227. flock/themes/hax0r-blue.toml +1 -1
  228. flock/themes/hopscotch.256.toml +1 -1
  229. flock/themes/ic-green-ppl.toml +1 -1
  230. flock/themes/iceberg-dark.toml +1 -1
  231. flock/themes/japanesque.toml +1 -1
  232. flock/themes/jubi.toml +1 -1
  233. flock/themes/kibble.toml +1 -1
  234. flock/themes/kolorit.toml +1 -1
  235. flock/themes/kurokula.toml +1 -1
  236. flock/themes/materialdesigncolors.toml +1 -1
  237. flock/themes/matrix.toml +1 -1
  238. flock/themes/mellifluous.toml +1 -1
  239. flock/themes/midnight-in-mojave.toml +1 -1
  240. flock/themes/monokai-remastered.toml +1 -1
  241. flock/themes/monokai-soda.toml +1 -1
  242. flock/themes/neon.toml +1 -1
  243. flock/themes/neopolitan.toml +5 -5
  244. flock/themes/nord-light.toml +1 -1
  245. flock/themes/ocean.toml +1 -1
  246. flock/themes/onehalfdark.toml +1 -1
  247. flock/themes/onehalflight.toml +1 -1
  248. flock/themes/palenighthc.toml +1 -1
  249. flock/themes/paulmillr.toml +1 -1
  250. flock/themes/pencildark.toml +1 -1
  251. flock/themes/pnevma.toml +1 -1
  252. flock/themes/purple-rain.toml +1 -1
  253. flock/themes/purplepeter.toml +1 -1
  254. flock/themes/raycast-dark.toml +1 -1
  255. flock/themes/red-sands.toml +1 -1
  256. flock/themes/relaxed.toml +1 -1
  257. flock/themes/retro.toml +1 -1
  258. flock/themes/rose-pine.toml +1 -1
  259. flock/themes/royal.toml +1 -1
  260. flock/themes/ryuuko.toml +1 -1
  261. flock/themes/sakura.toml +1 -1
  262. flock/themes/scarlet-protocol.toml +1 -1
  263. flock/themes/seoulbones-dark.toml +1 -1
  264. flock/themes/shades-of-purple.toml +1 -1
  265. flock/themes/smyck.toml +1 -1
  266. flock/themes/softserver.toml +1 -1
  267. flock/themes/solarized-darcula.toml +1 -1
  268. flock/themes/square.toml +1 -1
  269. flock/themes/sugarplum.toml +1 -1
  270. flock/themes/thayer-bright.toml +1 -1
  271. flock/themes/tokyonight.toml +1 -1
  272. flock/themes/tomorrow.toml +1 -1
  273. flock/themes/ubuntu.toml +1 -1
  274. flock/themes/ultradark.toml +1 -1
  275. flock/themes/ultraviolent.toml +1 -1
  276. flock/themes/unikitty.toml +1 -1
  277. flock/themes/urple.toml +1 -1
  278. flock/themes/vesper.toml +1 -1
  279. flock/themes/vimbones.toml +1 -1
  280. flock/themes/wildcherry.toml +1 -1
  281. flock/themes/wilmersdorf.toml +1 -1
  282. flock/themes/wryan.toml +1 -1
  283. flock/themes/xcodedarkhc.toml +1 -1
  284. flock/themes/xcodelight.toml +1 -1
  285. flock/themes/zenbones-light.toml +1 -1
  286. flock/themes/zenwritten-dark.toml +1 -1
  287. flock/utilities.py +301 -0
  288. flock/utility/output_utility_component.py +226 -0
  289. flock/visibility.py +107 -0
  290. flock_core-0.5.0.dist-info/METADATA +964 -0
  291. flock_core-0.5.0.dist-info/RECORD +525 -0
  292. flock_core-0.5.0.dist-info/entry_points.txt +2 -0
  293. {flock_core-0.4.543.dist-info → flock_core-0.5.0.dist-info}/licenses/LICENSE +1 -1
  294. flock/adapter/__init__.py +0 -14
  295. flock/adapter/azure_adapter.py +0 -68
  296. flock/adapter/chroma_adapter.py +0 -73
  297. flock/adapter/faiss_adapter.py +0 -97
  298. flock/adapter/pinecone_adapter.py +0 -51
  299. flock/adapter/vector_base.py +0 -47
  300. flock/cli/assets/release_notes.md +0 -140
  301. flock/cli/config.py +0 -8
  302. flock/cli/constants.py +0 -36
  303. flock/cli/create_agent.py +0 -1
  304. flock/cli/create_flock.py +0 -280
  305. flock/cli/execute_flock.py +0 -620
  306. flock/cli/load_agent.py +0 -1
  307. flock/cli/load_examples.py +0 -1
  308. flock/cli/load_flock.py +0 -192
  309. flock/cli/load_release_notes.py +0 -20
  310. flock/cli/loaded_flock_cli.py +0 -254
  311. flock/cli/manage_agents.py +0 -459
  312. flock/cli/registry_management.py +0 -889
  313. flock/cli/runner.py +0 -41
  314. flock/cli/settings.py +0 -857
  315. flock/cli/utils.py +0 -135
  316. flock/cli/view_results.py +0 -29
  317. flock/cli/yaml_editor.py +0 -396
  318. flock/config.py +0 -56
  319. flock/core/__init__.py +0 -44
  320. flock/core/api/__init__.py +0 -10
  321. flock/core/api/custom_endpoint.py +0 -45
  322. flock/core/api/endpoints.py +0 -262
  323. flock/core/api/main.py +0 -162
  324. flock/core/api/models.py +0 -101
  325. flock/core/api/run_store.py +0 -224
  326. flock/core/api/runner.py +0 -44
  327. flock/core/api/service.py +0 -214
  328. flock/core/config/flock_agent_config.py +0 -11
  329. flock/core/config/scheduled_agent_config.py +0 -40
  330. flock/core/context/context.py +0 -214
  331. flock/core/context/context_manager.py +0 -40
  332. flock/core/context/context_vars.py +0 -11
  333. flock/core/evaluation/utils.py +0 -395
  334. flock/core/execution/batch_executor.py +0 -369
  335. flock/core/execution/evaluation_executor.py +0 -438
  336. flock/core/execution/local_executor.py +0 -31
  337. flock/core/execution/opik_executor.py +0 -103
  338. flock/core/execution/temporal_executor.py +0 -166
  339. flock/core/flock.py +0 -1003
  340. flock/core/flock_agent.py +0 -1258
  341. flock/core/flock_evaluator.py +0 -60
  342. flock/core/flock_factory.py +0 -513
  343. flock/core/flock_module.py +0 -207
  344. flock/core/flock_registry.py +0 -702
  345. flock/core/flock_router.py +0 -83
  346. flock/core/flock_scheduler.py +0 -166
  347. flock/core/flock_server_manager.py +0 -136
  348. flock/core/interpreter/python_interpreter.py +0 -689
  349. flock/core/logging/live_capture.py +0 -137
  350. flock/core/logging/trace_and_logged.py +0 -59
  351. flock/core/mcp/__init__.py +0 -1
  352. flock/core/mcp/flock_mcp_server.py +0 -640
  353. flock/core/mcp/mcp_client_manager.py +0 -201
  354. flock/core/mcp/types/__init__.py +0 -1
  355. flock/core/mixin/dspy_integration.py +0 -445
  356. flock/core/mixin/prompt_parser.py +0 -125
  357. flock/core/serialization/__init__.py +0 -13
  358. flock/core/serialization/callable_registry.py +0 -52
  359. flock/core/serialization/flock_serializer.py +0 -854
  360. flock/core/serialization/json_encoder.py +0 -41
  361. flock/core/serialization/secure_serializer.py +0 -175
  362. flock/core/serialization/serializable.py +0 -342
  363. flock/core/serialization/serialization_utils.py +0 -409
  364. flock/core/util/file_path_utils.py +0 -223
  365. flock/core/util/hydrator.py +0 -309
  366. flock/core/util/input_resolver.py +0 -141
  367. flock/core/util/loader.py +0 -59
  368. flock/core/util/splitter.py +0 -219
  369. flock/di.py +0 -41
  370. flock/evaluators/__init__.py +0 -1
  371. flock/evaluators/declarative/__init__.py +0 -1
  372. flock/evaluators/declarative/declarative_evaluator.py +0 -217
  373. flock/evaluators/memory/memory_evaluator.py +0 -90
  374. flock/evaluators/test/test_case_evaluator.py +0 -38
  375. flock/evaluators/zep/zep_evaluator.py +0 -59
  376. flock/modules/__init__.py +0 -1
  377. flock/modules/assertion/__init__.py +0 -1
  378. flock/modules/assertion/assertion_module.py +0 -286
  379. flock/modules/callback/__init__.py +0 -1
  380. flock/modules/callback/callback_module.py +0 -91
  381. flock/modules/enterprise_memory/README.md +0 -99
  382. flock/modules/enterprise_memory/enterprise_memory_module.py +0 -526
  383. flock/modules/mem0/__init__.py +0 -1
  384. flock/modules/mem0/mem0_module.py +0 -126
  385. flock/modules/mem0_async/__init__.py +0 -1
  386. flock/modules/mem0_async/async_mem0_module.py +0 -126
  387. flock/modules/memory/__init__.py +0 -1
  388. flock/modules/memory/memory_module.py +0 -429
  389. flock/modules/memory/memory_parser.py +0 -125
  390. flock/modules/memory/memory_storage.py +0 -736
  391. flock/modules/output/__init__.py +0 -1
  392. flock/modules/output/output_module.py +0 -196
  393. flock/modules/performance/__init__.py +0 -1
  394. flock/modules/performance/metrics_module.py +0 -678
  395. flock/modules/zep/__init__.py +0 -1
  396. flock/modules/zep/zep_module.py +0 -192
  397. flock/platform/docker_tools.py +0 -49
  398. flock/platform/jaeger_install.py +0 -86
  399. flock/routers/__init__.py +0 -1
  400. flock/routers/agent/__init__.py +0 -1
  401. flock/routers/agent/agent_router.py +0 -236
  402. flock/routers/agent/handoff_agent.py +0 -58
  403. flock/routers/conditional/conditional_router.py +0 -486
  404. flock/routers/default/__init__.py +0 -1
  405. flock/routers/default/default_router.py +0 -80
  406. flock/routers/feedback/feedback_router.py +0 -114
  407. flock/routers/list_generator/list_generator_router.py +0 -166
  408. flock/routers/llm/__init__.py +0 -1
  409. flock/routers/llm/llm_router.py +0 -365
  410. flock/tools/__init__.py +0 -0
  411. flock/tools/azure_tools.py +0 -781
  412. flock/tools/code_tools.py +0 -167
  413. flock/tools/file_tools.py +0 -149
  414. flock/tools/github_tools.py +0 -157
  415. flock/tools/markdown_tools.py +0 -205
  416. flock/tools/system_tools.py +0 -9
  417. flock/tools/text_tools.py +0 -810
  418. flock/tools/web_tools.py +0 -92
  419. flock/tools/zendesk_tools.py +0 -501
  420. flock/webapp/__init__.py +0 -1
  421. flock/webapp/app/__init__.py +0 -0
  422. flock/webapp/app/api/__init__.py +0 -0
  423. flock/webapp/app/api/agent_management.py +0 -237
  424. flock/webapp/app/api/execution.py +0 -503
  425. flock/webapp/app/api/flock_management.py +0 -125
  426. flock/webapp/app/api/registry_viewer.py +0 -29
  427. flock/webapp/app/chat.py +0 -662
  428. flock/webapp/app/config.py +0 -104
  429. flock/webapp/app/dependencies.py +0 -117
  430. flock/webapp/app/main.py +0 -1086
  431. flock/webapp/app/middleware.py +0 -113
  432. flock/webapp/app/models_ui.py +0 -7
  433. flock/webapp/app/services/__init__.py +0 -0
  434. flock/webapp/app/services/feedback_file_service.py +0 -363
  435. flock/webapp/app/services/flock_service.py +0 -345
  436. flock/webapp/app/services/sharing_models.py +0 -81
  437. flock/webapp/app/services/sharing_store.py +0 -597
  438. flock/webapp/app/templates/theme_mapper.html +0 -326
  439. flock/webapp/app/theme_mapper.py +0 -811
  440. flock/webapp/app/utils.py +0 -85
  441. flock/webapp/run.py +0 -219
  442. flock/webapp/static/css/chat.css +0 -301
  443. flock/webapp/static/css/components.css +0 -167
  444. flock/webapp/static/css/header.css +0 -39
  445. flock/webapp/static/css/layout.css +0 -281
  446. flock/webapp/static/css/sidebar.css +0 -127
  447. flock/webapp/static/css/two-pane.css +0 -48
  448. flock/webapp/templates/base.html +0 -389
  449. flock/webapp/templates/chat.html +0 -152
  450. flock/webapp/templates/chat_settings.html +0 -19
  451. flock/webapp/templates/flock_editor.html +0 -16
  452. flock/webapp/templates/index.html +0 -12
  453. flock/webapp/templates/partials/_agent_detail_form.html +0 -93
  454. flock/webapp/templates/partials/_agent_list.html +0 -18
  455. flock/webapp/templates/partials/_agent_manager_view.html +0 -51
  456. flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
  457. flock/webapp/templates/partials/_chat_container.html +0 -15
  458. flock/webapp/templates/partials/_chat_messages.html +0 -57
  459. flock/webapp/templates/partials/_chat_settings_form.html +0 -85
  460. flock/webapp/templates/partials/_create_flock_form.html +0 -50
  461. flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
  462. flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
  463. flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
  464. flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
  465. flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
  466. flock/webapp/templates/partials/_env_vars_table.html +0 -23
  467. flock/webapp/templates/partials/_execution_form.html +0 -127
  468. flock/webapp/templates/partials/_execution_view_container.html +0 -28
  469. flock/webapp/templates/partials/_flock_file_list.html +0 -23
  470. flock/webapp/templates/partials/_flock_properties_form.html +0 -52
  471. flock/webapp/templates/partials/_flock_upload_form.html +0 -16
  472. flock/webapp/templates/partials/_header_flock_status.html +0 -5
  473. flock/webapp/templates/partials/_live_logs.html +0 -13
  474. flock/webapp/templates/partials/_load_manager_view.html +0 -49
  475. flock/webapp/templates/partials/_registry_table.html +0 -25
  476. flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
  477. flock/webapp/templates/partials/_results_display.html +0 -78
  478. flock/webapp/templates/partials/_settings_env_content.html +0 -9
  479. flock/webapp/templates/partials/_settings_theme_content.html +0 -14
  480. flock/webapp/templates/partials/_settings_view.html +0 -36
  481. flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
  482. flock/webapp/templates/partials/_share_link_snippet.html +0 -35
  483. flock/webapp/templates/partials/_sidebar.html +0 -74
  484. flock/webapp/templates/partials/_structured_data_view.html +0 -40
  485. flock/webapp/templates/partials/_theme_preview.html +0 -36
  486. flock/webapp/templates/registry_viewer.html +0 -84
  487. flock/webapp/templates/shared_run_page.html +0 -140
  488. flock/workflow/__init__.py +0 -0
  489. flock/workflow/activities.py +0 -237
  490. flock/workflow/agent_activities.py +0 -24
  491. flock/workflow/agent_execution_activity.py +0 -240
  492. flock/workflow/flock_workflow.py +0 -225
  493. flock/workflow/temporal_config.py +0 -96
  494. flock/workflow/temporal_setup.py +0 -60
  495. flock_core-0.4.543.dist-info/METADATA +0 -676
  496. flock_core-0.4.543.dist-info/RECORD +0 -572
  497. flock_core-0.4.543.dist-info/entry_points.txt +0 -2
  498. /flock/{core/logging → logging}/formatters/themes.py +0 -0
  499. /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
  500. /flock/{core/mcp → mcp}/util/__init__.py +0 -0
  501. {flock_core-0.4.543.dist-info → flock_core-0.5.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,450 @@
1
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { fetchArtifactSummary, fetchArtifacts, type ArtifactListItem, type ArtifactQueryOptions } from '../../services/api';
3
+ import { useFilterStore } from '../../store/filterStore';
4
+ import type { ModuleContext } from './ModuleRegistry';
5
+ import JsonAttributeRenderer from './JsonAttributeRenderer';
6
+ import styles from './HistoricalArtifactsModule.module.css';
7
+
8
+ const PAGE_SIZE = 100;
9
+ const ITEM_HEIGHT = 48;
10
+ const MIN_VISIBLE_ITEMS = 8;
11
+
12
+ type TimeRangeSelection = ReturnType<typeof useFilterStore.getState>['timeRange'];
13
+
14
+ type HistoricalArtifactsModuleProps = {
15
+ context: ModuleContext;
16
+ };
17
+
18
+ const resolveTimeRangeToIso = (range: TimeRangeSelection): { from?: string; to?: string } => {
19
+ const now = Date.now();
20
+ if (range.preset === 'last5min') {
21
+ return {
22
+ from: new Date(now - 5 * 60 * 1000).toISOString(),
23
+ to: new Date(now).toISOString(),
24
+ };
25
+ }
26
+ if (range.preset === 'last10min') {
27
+ return {
28
+ from: new Date(now - 10 * 60 * 1000).toISOString(),
29
+ to: new Date(now).toISOString(),
30
+ };
31
+ }
32
+ if (range.preset === 'last1hour') {
33
+ return {
34
+ from: new Date(now - 60 * 60 * 1000).toISOString(),
35
+ to: new Date(now).toISOString(),
36
+ };
37
+ }
38
+ if (range.preset === 'custom' && range.start && range.end) {
39
+ return {
40
+ from: new Date(range.start).toISOString(),
41
+ to: new Date(range.end).toISOString(),
42
+ };
43
+ }
44
+ return {};
45
+ };
46
+
47
+ const HistoricalArtifactsModule: React.FC<HistoricalArtifactsModuleProps> = ({ context }) => {
48
+ // Context reserved for future extensions (module lifecycle expects prop)
49
+ void context;
50
+ const correlationId = useFilterStore((state) => state.correlationId);
51
+ const timeRange = useFilterStore((state) => state.timeRange);
52
+ const selectedArtifactTypes = useFilterStore((state) => state.selectedArtifactTypes);
53
+ const selectedProducers = useFilterStore((state) => state.selectedProducers);
54
+ const selectedTags = useFilterStore((state) => state.selectedTags);
55
+ const selectedVisibility = useFilterStore((state) => state.selectedVisibility);
56
+ const setSummary = useFilterStore((state) => state.setSummary);
57
+ const updateAvailableCorrelationIds = useFilterStore((state) => state.updateAvailableCorrelationIds);
58
+ const summary = useFilterStore((state) => state.summary);
59
+
60
+ const [artifacts, setArtifacts] = useState<ArtifactListItem[]>([]);
61
+ const [nextOffset, setNextOffset] = useState(0);
62
+ const [total, setTotal] = useState(0);
63
+ const [loading, setLoading] = useState(false);
64
+ const [error, setError] = useState<string | null>(null);
65
+ const [selectedArtifactId, setSelectedArtifactId] = useState<string | null>(null);
66
+
67
+ const lastAutoLoadIndex = useRef(-1);
68
+ const virtualScrollRef = useRef<HTMLDivElement | null>(null);
69
+ const [virtualRange, setVirtualRange] = useState({ start: 0, end: MIN_VISIBLE_ITEMS });
70
+
71
+ const selectedArtifact = useMemo(
72
+ () => artifacts.find((artifact) => artifact.id === selectedArtifactId) ?? null,
73
+ [artifacts, selectedArtifactId]
74
+ );
75
+
76
+ const hasMore = total > nextOffset;
77
+
78
+ useEffect(() => {
79
+ if (selectedArtifactId && !artifacts.some((artifact) => artifact.id === selectedArtifactId)) {
80
+ setSelectedArtifactId(null);
81
+ }
82
+ }, [artifacts, selectedArtifactId]);
83
+
84
+ const buildQueryOptions = useCallback(
85
+ (offset: number): ArtifactQueryOptions => {
86
+ const range = resolveTimeRangeToIso(timeRange);
87
+ return {
88
+ types: selectedArtifactTypes,
89
+ producers: selectedProducers,
90
+ tags: selectedTags,
91
+ visibility: selectedVisibility,
92
+ correlationId,
93
+ from: range.from,
94
+ to: range.to,
95
+ limit: PAGE_SIZE,
96
+ offset,
97
+ embedMeta: true,
98
+ };
99
+ },
100
+ [timeRange, selectedArtifactTypes, selectedProducers, selectedTags, selectedVisibility, correlationId]
101
+ );
102
+
103
+ const mergeCorrelationMetadata = useCallback(
104
+ (items: ArtifactListItem[]) => {
105
+ if (items.length === 0) return;
106
+
107
+ const existing = useFilterStore.getState().availableCorrelationIds;
108
+ const merged = new Map(existing.map((item) => [item.correlation_id, { ...item }]));
109
+
110
+ items.forEach((item) => {
111
+ if (!item.correlation_id) return;
112
+ const timestamp = new Date(item.created_at).getTime();
113
+ const current = merged.get(item.correlation_id);
114
+ if (current) {
115
+ current.artifact_count += 1;
116
+ current.first_seen = Math.min(current.first_seen, timestamp);
117
+ } else {
118
+ merged.set(item.correlation_id, {
119
+ correlation_id: item.correlation_id,
120
+ first_seen: timestamp,
121
+ artifact_count: 1,
122
+ run_count: 0,
123
+ });
124
+ }
125
+ });
126
+
127
+ updateAvailableCorrelationIds(Array.from(merged.values()));
128
+ },
129
+ [updateAvailableCorrelationIds]
130
+ );
131
+
132
+ const loadArtifacts = useCallback(
133
+ async (reset: boolean) => {
134
+ setLoading(true);
135
+ try {
136
+ const offset = reset ? 0 : nextOffset;
137
+ const queryOptions = buildQueryOptions(offset);
138
+ const response = await fetchArtifacts(queryOptions);
139
+
140
+ setArtifacts((prev) => (reset ? response.items : [...prev, ...response.items]));
141
+ setNextOffset(offset + response.pagination.limit);
142
+ setTotal(response.pagination.total);
143
+ setError(null);
144
+
145
+ mergeCorrelationMetadata(response.items);
146
+
147
+ // UI Optimization Migration (Phase 2/4 - Spec 002): Backend-driven architecture
148
+ // Graph updates happen automatically via GraphCanvas useEffect when filters change
149
+ // This module only manages the artifact table view, not the graph
150
+ // No need to manually trigger graph updates here
151
+
152
+ const summaryResponse = await fetchArtifactSummary({
153
+ ...queryOptions,
154
+ limit: undefined,
155
+ offset: undefined,
156
+ });
157
+ setSummary(summaryResponse);
158
+ } catch (err) {
159
+ console.error('[HistoricalArtifactsModule] Failed to load artifacts', err);
160
+ setError('Failed to load artifacts');
161
+ } finally {
162
+ setLoading(false);
163
+ }
164
+ },
165
+ [buildQueryOptions, mergeCorrelationMetadata, nextOffset, setSummary]
166
+ );
167
+
168
+ useEffect(() => {
169
+ lastAutoLoadIndex.current = -1;
170
+ loadArtifacts(true);
171
+ }, [loadArtifacts]);
172
+
173
+ const rows = useMemo(
174
+ () =>
175
+ artifacts.map((artifact) => ({
176
+ id: artifact.id,
177
+ timestamp: new Date(artifact.created_at).toLocaleString(),
178
+ type: artifact.type,
179
+ producedBy: artifact.produced_by,
180
+ correlationId: artifact.correlation_id ?? '—',
181
+ tags: artifact.tags.join(', ') || '—',
182
+ visibility: artifact.visibility_kind || artifact.visibility?.kind || 'Unknown',
183
+ consumedCount: artifact.consumptions?.length ?? 0,
184
+ })),
185
+ [artifacts]
186
+ );
187
+
188
+ const handleLoadMore = () => {
189
+ if (!loading && hasMore) {
190
+ lastAutoLoadIndex.current = -1;
191
+ loadArtifacts(false);
192
+ }
193
+ };
194
+ const listHeight = useMemo(() => Math.max(MIN_VISIBLE_ITEMS, Math.min(rows.length || MIN_VISIBLE_ITEMS, 12)) * ITEM_HEIGHT, [rows.length]);
195
+
196
+ useEffect(() => {
197
+ const container = virtualScrollRef.current;
198
+ if (!container) {
199
+ return;
200
+ }
201
+
202
+ const handleScroll = () => {
203
+ const totalItems = rows.length;
204
+ if (totalItems === 0) {
205
+ setVirtualRange({ start: 0, end: MIN_VISIBLE_ITEMS });
206
+ return;
207
+ }
208
+
209
+ const scrollTop = container.scrollTop;
210
+ const viewportHeight = container.clientHeight;
211
+ const startIndex = Math.max(0, Math.floor(scrollTop / ITEM_HEIGHT) - 5);
212
+ const endIndex = Math.min(totalItems, Math.ceil((scrollTop + viewportHeight) / ITEM_HEIGHT) + 5);
213
+ setVirtualRange({ start: startIndex, end: endIndex });
214
+
215
+ if (hasMore && !loading && endIndex >= totalItems - 5 && lastAutoLoadIndex.current !== endIndex) {
216
+ lastAutoLoadIndex.current = endIndex;
217
+ handleLoadMore();
218
+ }
219
+ };
220
+
221
+ handleScroll();
222
+ container.addEventListener('scroll', handleScroll);
223
+ return () => container.removeEventListener('scroll', handleScroll);
224
+ }, [handleLoadMore, hasMore, loading, rows.length]);
225
+
226
+ useEffect(() => {
227
+ const container = virtualScrollRef.current;
228
+ if (container) {
229
+ container.scrollTop = 0;
230
+ }
231
+ setVirtualRange({ start: 0, end: Math.max(MIN_VISIBLE_ITEMS, Math.min(rows.length, MIN_VISIBLE_ITEMS * 2)) });
232
+ lastAutoLoadIndex.current = -1;
233
+ }, [rows.length]);
234
+
235
+ const retentionInfo = useMemo(() => {
236
+ if (!summary?.earliest_created_at || !summary?.latest_created_at) {
237
+ return null;
238
+ }
239
+ const earliest = new Date(summary.earliest_created_at);
240
+ const latest = new Date(summary.latest_created_at);
241
+ const spanMs = Math.max(0, latest.getTime() - earliest.getTime());
242
+ const spanDays = spanMs / (1000 * 60 * 60 * 24);
243
+ let spanLabel: string;
244
+ if (spanDays >= 2) {
245
+ spanLabel = `${spanDays.toFixed(1)} days`;
246
+ } else if (spanDays >= 0.5) {
247
+ spanLabel = `${(spanDays * 24).toFixed(0)} hours`;
248
+ } else {
249
+ spanLabel = `${Math.max(1, Math.round(spanMs / (1000 * 60)))} minutes`;
250
+ }
251
+ return {
252
+ earliest: earliest.toLocaleString(),
253
+ latest: latest.toLocaleString(),
254
+ spanLabel,
255
+ };
256
+ }, [summary]);
257
+
258
+ return (
259
+ <div className={styles.container}>
260
+ <header className={styles.header}>
261
+ <div className={styles.metrics}>
262
+ <div>
263
+ <span className={styles.metricLabel}>Artifacts</span>
264
+ <span className={styles.metricValue}>{total}</span>
265
+ </div>
266
+ <div>
267
+ <span className={styles.metricLabel}>Earliest</span>
268
+ <span className={styles.metricValue}>
269
+ {summary?.earliest_created_at ? new Date(summary.earliest_created_at).toLocaleString() : '—'}
270
+ </span>
271
+ </div>
272
+ <div>
273
+ <span className={styles.metricLabel}>Latest</span>
274
+ <span className={styles.metricValue}>
275
+ {summary?.latest_created_at ? new Date(summary.latest_created_at).toLocaleString() : '—'}
276
+ </span>
277
+ </div>
278
+ </div>
279
+ <div className={styles.actions}>
280
+ <button type="button" onClick={() => loadArtifacts(true)} disabled={loading}>
281
+ Refresh
282
+ </button>
283
+ <button type="button" onClick={handleLoadMore} disabled={loading || !hasMore}>
284
+ Load Older
285
+ </button>
286
+ </div>
287
+ </header>
288
+
289
+ {retentionInfo && (
290
+ <div className={styles.retentionBanner}>
291
+ <span>
292
+ Historical window: <strong>{retentionInfo.spanLabel}</strong> (oldest artifact {retentionInfo.earliest})
293
+ </span>
294
+ <span>
295
+ Latest artifact recorded at <strong>{retentionInfo.latest}</strong>.{' '}
296
+ {hasMore ? 'Use “Load Older” to fetch additional retained history.' : 'You are viewing the full retained history.'}
297
+ </span>
298
+ </div>
299
+ )}
300
+
301
+ {error && <div className={styles.error}>{error}</div>}
302
+
303
+ {!loading && artifacts.length === 0 && !error && (
304
+ <div className={styles.emptyState}>No artifacts found for current filters.</div>
305
+ )}
306
+
307
+ {artifacts.length > 0 && (
308
+ <div className={styles.contentArea}>
309
+ <div className={styles.tableContainer}>
310
+ <div className={styles.headerRow}>
311
+ <span>Timestamp</span>
312
+ <span>Type</span>
313
+ <span>Produced By</span>
314
+ <span>Correlation ID</span>
315
+ <span>Tags</span>
316
+ <span>Visibility</span>
317
+ <span>Consumed</span>
318
+ </div>
319
+ <div
320
+ ref={virtualScrollRef}
321
+ className={styles.virtualViewport}
322
+ style={{ height: listHeight }}
323
+ >
324
+ <div style={{ height: rows.length * ITEM_HEIGHT, position: 'relative' }}>
325
+ <div
326
+ style={{
327
+ position: 'absolute',
328
+ top: virtualRange.start * ITEM_HEIGHT,
329
+ left: 0,
330
+ right: 0,
331
+ }}
332
+ >
333
+ {rows.slice(virtualRange.start, virtualRange.end).map((row, idx) => {
334
+ const absoluteIndex = virtualRange.start + idx;
335
+ const isSelected = row.id === selectedArtifactId;
336
+ const classes = [styles.dataRow];
337
+ if (absoluteIndex % 2 === 1) {
338
+ classes.push(styles.dataRowStripe);
339
+ }
340
+ if (isSelected) {
341
+ classes.push(styles.dataRowSelected);
342
+ }
343
+ return (
344
+ <div
345
+ key={row.id}
346
+ className={classes.join(' ')}
347
+ style={{ height: ITEM_HEIGHT }}
348
+ role="button"
349
+ tabIndex={0}
350
+ aria-selected={isSelected}
351
+ onClick={() => setSelectedArtifactId(row.id)}
352
+ onKeyDown={(event) => {
353
+ if (event.key === 'Enter' || event.key === ' ') {
354
+ event.preventDefault();
355
+ setSelectedArtifactId(row.id);
356
+ }
357
+ }}
358
+ >
359
+ <span>{row.timestamp}</span>
360
+ <span>{row.type}</span>
361
+ <span>{row.producedBy}</span>
362
+ <span>{row.correlationId}</span>
363
+ <span>{row.tags}</span>
364
+ <span>{row.visibility}</span>
365
+ <span>{row.consumedCount}</span>
366
+ </div>
367
+ );
368
+ })}
369
+ </div>
370
+ </div>
371
+ </div>
372
+ </div>
373
+ <aside className={styles.detailPanel}>
374
+ {selectedArtifact ? (
375
+ <>
376
+ <div className={styles.detailHeader}>
377
+ <div>
378
+ <h3>{selectedArtifact.type}</h3>
379
+ <p>{new Date(selectedArtifact.created_at).toLocaleString()}</p>
380
+ </div>
381
+ <button type="button" onClick={() => setSelectedArtifactId(null)}>
382
+ Clear
383
+ </button>
384
+ </div>
385
+ <div className={styles.detailSection}>
386
+ <h4>Metadata</h4>
387
+ <dl className={styles.detailList}>
388
+ <div>
389
+ <dt>Produced By</dt>
390
+ <dd>{selectedArtifact.produced_by}</dd>
391
+ </div>
392
+ <div>
393
+ <dt>Correlation</dt>
394
+ <dd>{selectedArtifact.correlation_id || '—'}</dd>
395
+ </div>
396
+ <div>
397
+ <dt>Partition</dt>
398
+ <dd>{selectedArtifact.partition_key || '—'}</dd>
399
+ </div>
400
+ <div>
401
+ <dt>Tags</dt>
402
+ <dd>{selectedArtifact.tags.length ? selectedArtifact.tags.join(', ') : '—'}</dd>
403
+ </div>
404
+ <div>
405
+ <dt>Visibility</dt>
406
+ <dd>{selectedArtifact.visibility_kind || selectedArtifact.visibility?.kind || 'Unknown'}</dd>
407
+ </div>
408
+ <div>
409
+ <dt>Consumed By</dt>
410
+ <dd>{selectedArtifact.consumed_by?.length ? selectedArtifact.consumed_by.join(', ') : '—'}</dd>
411
+ </div>
412
+ </dl>
413
+ </div>
414
+ <div className={styles.detailSection}>
415
+ <h4>Payload</h4>
416
+ <JsonAttributeRenderer
417
+ value={JSON.stringify(selectedArtifact.payload, null, 2)}
418
+ maxStringLength={Number.POSITIVE_INFINITY}
419
+ />
420
+ </div>
421
+ <div className={styles.detailSection}>
422
+ <h4>Consumption History</h4>
423
+ {selectedArtifact.consumptions && selectedArtifact.consumptions.length > 0 ? (
424
+ <ul className={styles.consumptionList}>
425
+ {selectedArtifact.consumptions.map((entry) => (
426
+ <li key={`${entry.consumer}-${entry.consumed_at}`}>
427
+ <span className={styles.consumerName}>{entry.consumer}</span>
428
+ <span>{new Date(entry.consumed_at).toLocaleString()}</span>
429
+ {entry.run_id ? <span className={styles.runBadge}>Run {entry.run_id}</span> : null}
430
+ </li>
431
+ ))}
432
+ </ul>
433
+ ) : (
434
+ <p className={styles.emptyConsumption}>No consumers recorded for this artifact.</p>
435
+ )}
436
+ </div>
437
+ </>
438
+ ) : (
439
+ <div className={styles.emptyDetail}>Select an artifact to inspect payload and history.</div>
440
+ )}
441
+ </aside>
442
+ </div>
443
+ )}
444
+
445
+ {loading && <div className={styles.loading}>Loading…</div>}
446
+ </div>
447
+ );
448
+ };
449
+
450
+ export default HistoricalArtifactsModule;
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import type { ModuleContext } from './ModuleRegistry';
3
+ import HistoricalArtifactsModule from './HistoricalArtifactsModule';
4
+
5
+ interface HistoricalArtifactsModuleWrapperProps {
6
+ context: ModuleContext;
7
+ }
8
+
9
+ const HistoricalArtifactsModuleWrapper: React.FC<HistoricalArtifactsModuleWrapperProps> = ({ context }) => {
10
+ return <HistoricalArtifactsModule context={context} />;
11
+ };
12
+
13
+ export default HistoricalArtifactsModuleWrapper;
@@ -0,0 +1,140 @@
1
+ import React, { useState } from 'react';
2
+ import JsonView from '@uiw/react-json-view';
3
+
4
+ interface JsonAttributeRendererProps {
5
+ value: string;
6
+ maxStringLength?: number;
7
+ }
8
+
9
+ /**
10
+ * Renders an attribute value, parsing it as JSON if possible and displaying
11
+ * it with a beautiful collapsible JSON viewer. Falls back to plain text if not JSON.
12
+ */
13
+ const JsonAttributeRenderer: React.FC<JsonAttributeRendererProps> = ({
14
+ value,
15
+ maxStringLength = 200
16
+ }) => {
17
+ const [collapsed, setCollapsed] = useState<boolean | number>(2);
18
+
19
+ // Try to parse as JSON
20
+ try {
21
+ const parsed = JSON.parse(value);
22
+
23
+ // If it's a simple primitive after parsing, just show it as text
24
+ if (typeof parsed === 'string' || typeof parsed === 'number' || typeof parsed === 'boolean' || parsed === null) {
25
+ return (
26
+ <div style={{
27
+ fontFamily: 'var(--font-family-mono)',
28
+ fontSize: 'var(--font-size-body-xs)',
29
+ color: 'var(--color-text-secondary)',
30
+ wordBreak: 'break-word',
31
+ }}>
32
+ {String(parsed)}
33
+ </div>
34
+ );
35
+ }
36
+
37
+ // It's a complex object or array - use JSON viewer
38
+ return (
39
+ <div>
40
+ <div style={{
41
+ display: 'flex',
42
+ gap: 'var(--gap-xs)',
43
+ marginBottom: 'var(--gap-xs)',
44
+ }}>
45
+ <button
46
+ onClick={() => setCollapsed(false)}
47
+ style={{
48
+ padding: '2px 8px',
49
+ fontSize: 'var(--font-size-body-xs)',
50
+ color: 'var(--color-text-secondary)',
51
+ backgroundColor: 'var(--color-bg-elevated)',
52
+ border: '1px solid var(--color-border-subtle)',
53
+ borderRadius: 'var(--radius-xs)',
54
+ cursor: 'pointer',
55
+ fontFamily: 'var(--font-family-mono)',
56
+ }}
57
+ onMouseEnter={(e) => {
58
+ e.currentTarget.style.backgroundColor = 'var(--color-bg-hover)';
59
+ }}
60
+ onMouseLeave={(e) => {
61
+ e.currentTarget.style.backgroundColor = 'var(--color-bg-elevated)';
62
+ }}
63
+ >
64
+ Expand All
65
+ </button>
66
+ <button
67
+ onClick={() => setCollapsed(true)}
68
+ style={{
69
+ padding: '2px 8px',
70
+ fontSize: 'var(--font-size-body-xs)',
71
+ color: 'var(--color-text-secondary)',
72
+ backgroundColor: 'var(--color-bg-elevated)',
73
+ border: '1px solid var(--color-border-subtle)',
74
+ borderRadius: 'var(--radius-xs)',
75
+ cursor: 'pointer',
76
+ fontFamily: 'var(--font-family-mono)',
77
+ }}
78
+ onMouseEnter={(e) => {
79
+ e.currentTarget.style.backgroundColor = 'var(--color-bg-hover)';
80
+ }}
81
+ onMouseLeave={(e) => {
82
+ e.currentTarget.style.backgroundColor = 'var(--color-bg-elevated)';
83
+ }}
84
+ >
85
+ Collapse All
86
+ </button>
87
+ </div>
88
+ <div style={{
89
+ maxHeight: '400px',
90
+ overflowY: 'auto',
91
+ overflowX: 'auto',
92
+ }}>
93
+ <JsonView
94
+ value={parsed}
95
+ collapsed={collapsed}
96
+ displayDataTypes={false}
97
+ shortenTextAfterLength={0}
98
+ style={{
99
+ backgroundColor: 'var(--color-bg-elevated)',
100
+ fontSize: 'var(--font-size-body-xs)',
101
+ fontFamily: 'var(--font-family-mono)',
102
+ padding: 'var(--space-component-sm)',
103
+ borderRadius: 'var(--radius-sm)',
104
+ '--w-rjv-line-color': 'var(--color-text-tertiary)',
105
+ '--w-rjv-key-string': 'var(--color-primary-500)',
106
+ '--w-rjv-info-color': 'var(--color-text-secondary)',
107
+ '--w-rjv-curlybraces-color': 'var(--color-text-tertiary)',
108
+ '--w-rjv-brackets-color': 'var(--color-text-tertiary)',
109
+ '--w-rjv-arrow-color': 'var(--color-text-tertiary)',
110
+ '--w-rjv-edit-color': 'var(--color-primary-500)',
111
+ '--w-rjv-add-color': 'var(--color-success)',
112
+ '--w-rjv-del-color': 'var(--color-error)',
113
+ '--w-rjv-update-color': 'var(--color-warning)',
114
+ '--w-rjv-border-left-color': 'var(--color-border-subtle)',
115
+ } as React.CSSProperties}
116
+ />
117
+ </div>
118
+ </div>
119
+ );
120
+ } catch (e) {
121
+ // Not valid JSON - display as plain text with word wrap
122
+ const displayValue = value.length > maxStringLength
123
+ ? value.substring(0, maxStringLength) + '...'
124
+ : value;
125
+
126
+ return (
127
+ <div style={{
128
+ fontFamily: 'var(--font-family-mono)',
129
+ fontSize: 'var(--font-size-body-xs)',
130
+ color: 'var(--color-text-secondary)',
131
+ wordBreak: 'break-word',
132
+ whiteSpace: 'pre-wrap',
133
+ }}>
134
+ {displayValue}
135
+ </div>
136
+ );
137
+ }
138
+ };
139
+
140
+ export default JsonAttributeRenderer;