flock-core 0.5.0b71__py3-none-any.whl → 0.5.1__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/agent.py +39 -1
- flock/artifacts.py +17 -10
- flock/cli.py +1 -1
- flock/dashboard/__init__.py +2 -0
- flock/dashboard/collector.py +282 -6
- flock/dashboard/events.py +6 -0
- flock/dashboard/graph_builder.py +563 -0
- flock/dashboard/launcher.py +11 -6
- flock/dashboard/models/__init__.py +1 -0
- flock/dashboard/models/graph.py +156 -0
- flock/dashboard/service.py +175 -14
- 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 +2 -2
- flock/engines/dspy_engine.py +294 -20
- flock/frontend/README.md +6 -6
- flock/frontend/src/App.tsx +23 -31
- flock/frontend/src/__tests__/integration/graph-snapshot.test.tsx +647 -0
- flock/frontend/src/components/details/DetailWindowContainer.tsx +13 -17
- flock/frontend/src/components/details/MessageDetailWindow.tsx +439 -0
- flock/frontend/src/components/details/MessageHistoryTab.tsx +128 -53
- flock/frontend/src/components/details/RunStatusTab.tsx +79 -38
- flock/frontend/src/components/graph/AgentNode.test.tsx +3 -1
- flock/frontend/src/components/graph/AgentNode.tsx +8 -6
- flock/frontend/src/components/graph/GraphCanvas.tsx +13 -8
- flock/frontend/src/components/graph/MessageNode.test.tsx +3 -1
- flock/frontend/src/components/graph/MessageNode.tsx +16 -3
- flock/frontend/src/components/layout/DashboardLayout.tsx +12 -9
- flock/frontend/src/components/modules/HistoricalArtifactsModule.tsx +4 -14
- flock/frontend/src/components/modules/ModuleRegistry.ts +5 -3
- flock/frontend/src/hooks/useModules.ts +12 -4
- flock/frontend/src/hooks/usePersistence.ts +5 -3
- flock/frontend/src/services/api.ts +3 -19
- flock/frontend/src/services/graphService.test.ts +330 -0
- flock/frontend/src/services/graphService.ts +75 -0
- flock/frontend/src/services/websocket.ts +104 -268
- flock/frontend/src/store/filterStore.test.ts +89 -1
- flock/frontend/src/store/filterStore.ts +38 -16
- flock/frontend/src/store/graphStore.test.ts +538 -173
- flock/frontend/src/store/graphStore.ts +374 -465
- flock/frontend/src/store/moduleStore.ts +51 -33
- flock/frontend/src/store/uiStore.ts +23 -11
- flock/frontend/src/types/graph.ts +77 -44
- flock/frontend/src/utils/mockData.ts +16 -3
- flock/frontend/vite.config.ts +2 -2
- flock/orchestrator.py +27 -7
- flock/patches/__init__.py +5 -0
- flock/patches/dspy_streaming_patch.py +82 -0
- flock/service.py +2 -2
- flock/store.py +169 -4
- flock/themes/darkmatrix.toml +2 -2
- flock/themes/deep.toml +2 -2
- flock/themes/neopolitan.toml +4 -4
- {flock_core-0.5.0b71.dist-info → flock_core-0.5.1.dist-info}/METADATA +20 -13
- {flock_core-0.5.0b71.dist-info → flock_core-0.5.1.dist-info}/RECORD +59 -53
- flock/frontend/src/__tests__/e2e/critical-scenarios.test.tsx +0 -586
- flock/frontend/src/__tests__/integration/filtering-e2e.test.tsx +0 -391
- flock/frontend/src/__tests__/integration/graph-rendering.test.tsx +0 -640
- flock/frontend/src/services/websocket.test.ts +0 -595
- flock/frontend/src/utils/transforms.test.ts +0 -860
- flock/frontend/src/utils/transforms.ts +0 -323
- {flock_core-0.5.0b71.dist-info → flock_core-0.5.1.dist-info}/WHEEL +0 -0
- {flock_core-0.5.0b71.dist-info → flock_core-0.5.1.dist-info}/entry_points.txt +0 -0
- {flock_core-0.5.0b71.dist-info → flock_core-0.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}._container_18lbh_1{position:relative;width:300px}._inputWrapper_18lbh_11{position:relative}._input_18lbh_11{width:100%;padding:var(--spacing-2) var(--spacing-8) var(--spacing-2) var(--spacing-3);background-color:var(--color-bg-surface);border:1px solid var(--color-border-default);border-radius:var(--radius-md);font-size:var(--font-size-body-sm);font-family:var(--font-family-sans);color:var(--color-text-primary);outline:none;box-sizing:border-box;transition:var(--transition-colors),box-shadow var(--duration-normal) var(--ease-smooth)}._input_18lbh_11::placeholder{color:var(--color-text-muted);font-style:italic}._input_18lbh_11:focus{border-color:var(--color-border-focus);box-shadow:var(--shadow-glow-primary)}._clearButton_18lbh_67{position:absolute;right:var(--spacing-2);top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;font-size:18px;color:var(--color-text-muted);padding:0 var(--spacing-1);line-height:1;transition:var(--transition-colors)}._clearButton_18lbh_67:hover{color:var(--color-text-secondary)}._dropdown_18lbh_105{position:absolute;top:100%;left:0;right:0;margin-top:var(--spacing-1);background-color:var(--color-bg-surface);border:1px solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);max-height:300px;overflow-y:auto;z-index:1000}._dropdownEmpty_18lbh_135{padding:var(--spacing-3);color:var(--color-text-muted);font-size:var(--font-size-body-sm);text-align:center}._dropdownItem_18lbh_149{padding:var(--spacing-2-5) var(--spacing-3);cursor:pointer;border-bottom:1px solid var(--color-border-subtle);transition:var(--transition-colors)}._dropdownItem_18lbh_149:last-child{border-bottom:none}._dropdownItem_18lbh_149:hover{background-color:var(--color-bg-elevated)}._correlationId_18lbh_179{font-family:var(--font-family-mono);font-size:var(--font-size-body-xs);font-weight:var(--font-weight-medium);color:var(--color-text-primary);margin-bottom:var(--spacing-1);word-break:break-all}._metadata_18lbh_197{font-size:var(--font-size-caption);color:var(--color-text-tertiary)}._container_kluuc_1{display:flex;flex-direction:column;gap:var(--spacing-2)}._presetButtons_kluuc_13{display:flex;flex-wrap:wrap;gap:var(--spacing-2);align-items:center}._presetButton_kluuc_13{padding:var(--spacing-2) var(--spacing-4);background-color:var(--color-bg-surface);color:var(--color-text-secondary);border:1px solid var(--color-border-default);border-radius:var(--radius-md);cursor:pointer;font-size:var(--font-size-body-sm);font-weight:var(--font-weight-medium);font-family:var(--font-family-sans);transition:var(--transition-colors);white-space:nowrap}._presetButton_kluuc_13:hover{background-color:var(--color-bg-overlay);border-color:var(--color-border-strong)}._presetButton_kluuc_13._active_kluuc_65{background-color:var(--color-primary-600);color:var(--color-text-on-primary);border-color:var(--color-primary-600)}._presetButton_kluuc_13._active_kluuc_65:hover{background-color:var(--color-primary-700);border-color:var(--color-primary-700)}._presetButtonAll_kluuc_87{background:#c241f426;color:var(--color-secondary-200);border-color:var(--color-secondary-500)}._presetButtonAll_kluuc_87:hover{background:#c241f440;border-color:var(--color-secondary-400);color:var(--color-secondary-100)}._presetButtonAll_kluuc_87._active_kluuc_65{background:var(--color-secondary-500);border-color:var(--color-secondary-300);color:var(--color-text-on-primary)}._presetButtonAll_kluuc_87._active_kluuc_65:hover{background:var(--color-secondary-400);border-color:var(--color-secondary-200)}._customRange_kluuc_133{display:flex;gap:var(--spacing-3);align-items:center;padding:var(--spacing-2);background-color:var(--color-bg-surface);border-radius:var(--radius-md);border:1px solid var(--color-border-subtle)}._dateInputGroup_kluuc_153{display:flex;flex-direction:column;gap:var(--spacing-1)}._dateLabel_kluuc_165{font-size:var(--font-size-caption);color:var(--color-text-tertiary);font-weight:var(--font-weight-medium)}._dateInput_kluuc_153{padding:var(--spacing-1-5) var(--spacing-2);background-color:var(--color-bg-elevated);border:1px solid var(--color-border-default);border-radius:var(--radius-md);font-size:var(--font-size-body-sm);font-family:var(--font-family-sans);color:var(--color-text-primary);outline:none;transition:var(--transition-colors),box-shadow var(--duration-normal) var(--ease-smooth)}._dateInput_kluuc_153:focus{border-color:var(--color-border-focus);box-shadow:var(--shadow-glow-primary)}._dateInput_kluuc_153::-webkit-calendar-picker-indicator{cursor:pointer;filter:invert(.7);transition:var(--transition-opacity)}._dateInput_kluuc_153::-webkit-calendar-picker-indicator:hover{filter:invert(1)}._container_9ted7_1{display:flex;flex-direction:column;gap:var(--gap-xs)}._controlsRow_9ted7_13{display:flex;align-items:center;gap:var(--gap-sm);flex-wrap:wrap}._select_9ted7_27{min-width:180px;padding:var(--spacing-1) var(--spacing-2);border-radius:var(--radius-sm);border:1px solid var(--color-border-subtle);background:#00000059;color:var(--color-text-primary)}._saveButton_9ted7_45,._applyButton_9ted7_47,._deleteButton_9ted7_49{padding:var(--spacing-1) var(--spacing-3);border-radius:var(--radius-sm);border:none;font-size:var(--font-size-body-xs);cursor:pointer;transition:background-color var(--duration-fast) ease}._saveButton_9ted7_45{background:var(--color-info);color:var(--color-text-on-primary)}._applyButton_9ted7_47{background:var(--color-success);color:var(--color-text-on-primary)}._deleteButton_9ted7_49{background:var(--color-error);color:var(--color-text-on-primary)}._saveButton_9ted7_45:disabled,._applyButton_9ted7_47:disabled,._deleteButton_9ted7_49:disabled,._select_9ted7_27:disabled{opacity:.5;cursor:not-allowed}._error_9ted7_113{font-size:var(--font-size-body-xs);color:var(--color-error)}._panel_knkln_1{position:fixed;top:0;left:0;bottom:0;width:420px;background:var(--color-glass-bg);-webkit-backdrop-filter:blur(var(--blur-lg));backdrop-filter:blur(var(--blur-lg));border-right:var(--border-default);box-shadow:var(--shadow-2xl);z-index:1100;animation:_slideInLeft_knkln_1 var(--duration-slow) var(--ease-smooth);display:flex;flex-direction:column}._header_knkln_33{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--space-component-sm);padding:var(--space-layout-md);border-bottom:var(--border-subtle)}._title_knkln_51{margin:0;font-size:var(--font-size-h3);color:var(--color-text-primary)}._subtitle_knkln_63{margin:0;font-size:var(--font-size-body-xs);color:var(--color-text-tertiary)}._closeButton_knkln_75{width:32px;height:32px;border-radius:var(--radius-md);border:none;background:transparent;color:var(--color-text-secondary);font-size:22px;cursor:pointer;transition:var(--transition-all)}._closeButton_knkln_75:hover{background:var(--color-bg-overlay);color:var(--color-text-primary)}._content_knkln_109{flex:1;overflow-y:auto;padding:var(--space-layout-md);display:flex;flex-direction:column;gap:var(--space-layout-md)}._section_knkln_127{display:flex;flex-direction:column;gap:var(--space-component-sm)}._sectionLabel_knkln_139{margin:0;font-size:var(--font-size-body-xs);letter-spacing:var(--letter-spacing-wide);color:var(--color-text-tertiary);text-transform:uppercase}._separator_knkln_155{width:100%;height:1px;background:linear-gradient(90deg,transparent,rgba(148,163,184,.25),transparent);margin:var(--space-component-md) 0}@keyframes _slideInLeft_knkln_1{0%{transform:translate(-40px);opacity:0}to{transform:translate(0);opacity:1}}@media (max-width: 960px){._panel_knkln_1{width:100%}}._wrapper_1qq57_1{display:flex;align-items:center;width:100%;gap:var(--gap-md)}._container_1qq57_15{display:inline-flex;align-items:center;flex-wrap:wrap;gap:var(--gap-md);pointer-events:auto;margin-left:0;padding:0;max-width:100%}._toggleButton_1qq57_37{display:inline-flex;align-items:center;gap:var(--gap-sm);padding:var(--spacing-1) var(--spacing-3);border-radius:var(--radius-full);border:var(--border-subtle);background:color-mix(in srgb,var(--color-bg-surface) 80%,transparent);color:var(--color-text-secondary);font-size:var(--font-size-body-sm);font-weight:var(--font-weight-medium);letter-spacing:var(--letter-spacing-wide);text-transform:uppercase;cursor:pointer;transition:var(--transition-colors),var(--transition-transform),var(--transition-shadow)}._toggleButton_1qq57_37:hover{color:var(--color-text-primary);border-color:color-mix(in srgb,var(--color-border-focus) 60%,transparent);background:color-mix(in srgb,var(--color-bg-overlay) 75%,transparent)}._toggleButton_1qq57_37:focus-visible{outline:none;box-shadow:var(--shadow-glow-primary);color:var(--color-text-primary)}._toggleButton_1qq57_37:active{transform:scale(.98)}._toggleButtonActive_1qq57_103{color:var(--color-text-on-primary);background:linear-gradient(135deg,var(--color-primary-500) 0%,var(--color-primary-600) 100%);border-color:color-mix(in srgb,var(--color-primary-400) 70%,transparent);box-shadow:var(--shadow-sm)}._toggleButtonActive_1qq57_103:hover{box-shadow:var(--shadow-md)}._toggleIcon_1qq57_125{display:inline-flex;width:1rem;height:1rem}._toggleIcon_1qq57_125 svg{width:100%;height:100%}._toggleButtonActive_1qq57_103 ._toggleIcon_1qq57_125{color:var(--color-text-on-primary)}._toggleLabel_1qq57_155{letter-spacing:var(--letter-spacing-wide)}._pill_1qq57_163{--pill-accent: var(--color-primary-500);--pill-accent-soft: color-mix(in srgb, var(--color-bg-overlay) 88%, var(--pill-accent) 12%);--pill-border: color-mix(in srgb, var(--pill-accent) 45%, transparent);--pill-shadow: 0 12px 28px -18px color-mix(in srgb, var(--pill-accent) 40%, transparent);display:inline-flex;align-items:center;gap:var(--gap-sm);padding:var(--spacing-1-5) var(--spacing-3);border-radius:var(--radius-full);background:var(--color-bg-overlay);background:linear-gradient(135deg,var(--pill-accent-soft) 0%,color-mix(in srgb,var(--color-bg-surface) 92%,transparent) 100%);border:1px solid var(--pill-border);color:var(--color-text-primary);box-shadow:var(--shadow-xs),var(--pill-shadow);transition:var(--transition-transform),var(--transition-shadow),var(--transition-colors);cursor:default;animation:_fadeIn_1qq57_1 var(--duration-normal) var(--ease-out)}._pill_1qq57_163:hover{transform:translateY(-2px);box-shadow:0 16px 32px -18px color-mix(in srgb,var(--pill-accent) 55%,transparent)}._pill_1qq57_163:focus-within{box-shadow:0 16px 32px -18px color-mix(in srgb,var(--pill-accent) 55%,transparent),0 0 0 2px color-mix(in srgb,var(--pill-accent) 35%,transparent)}._pillAccent_1qq57_227{width:.75rem;height:.75rem;border-radius:var(--radius-full);flex-shrink:0;background:var(--pill-accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--pill-accent) 25%,transparent)}._textGroup_1qq57_245{display:flex;flex-direction:column;gap:2px;line-height:1.1}._pillTitle_1qq57_259{font-size:var(--font-size-tiny);font-weight:var(--font-weight-medium);letter-spacing:var(--letter-spacing-wide);text-transform:uppercase;color:var(--color-text-tertiary)}._pillValue_1qq57_275{font-size:var(--font-size-body-sm);font-weight:var(--font-weight-semibold);color:var(--color-text-primary);line-height:1.3}._removeButton_1qq57_289{background:none;border:none;margin-left:var(--gap-sm);display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;border-radius:var(--radius-full);color:var(--color-text-tertiary);transition:var(--transition-transform),var(--transition-colors),var(--transition-shadow);cursor:pointer}._removeButton_1qq57_289:hover,._removeButton_1qq57_289:focus-visible{color:var(--color-text-primary);background:color-mix(in srgb,var(--pill-accent) 18%,transparent)}._removeButton_1qq57_289:focus-visible{outline:none;box-shadow:0 0 0 2px color-mix(in srgb,var(--pill-accent) 35%,transparent)}._removeButton_1qq57_289:active{transform:scale(.92)}._removeIcon_1qq57_349{font-size:var(--font-size-body);line-height:1}._pill_1qq57_163[data-filter-type=timeRange]{--pill-accent: var(--color-tertiary-500)}._pill_1qq57_163[data-filter-type=artifactTypes]{--pill-accent: var(--color-secondary-500)}._pill_1qq57_163[data-filter-type=producers]{--pill-accent: var(--color-success)}._pill_1qq57_163[data-filter-type=tags]{--pill-accent: var(--color-secondary-400)}._pill_1qq57_163[data-filter-type=visibility]{--pill-accent: var(--color-info)}@media (max-width: 768px){._wrapper_1qq57_1{width:100%}._container_1qq57_15{border-radius:var(--radius-xl);width:100%}}@keyframes _fadeIn_1qq57_1{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}.publish-control-panel{position:fixed;top:0;right:0;bottom:0;width:400px;z-index:1000;background:var(--color-glass-bg);-webkit-backdrop-filter:blur(var(--blur-lg));backdrop-filter:blur(var(--blur-lg));border-left:var(--border-default);box-shadow:var(--shadow-xl);animation:slideInRight var(--duration-slow) var(--ease-smooth)}.publish-control-panel-inner{display:flex;flex-direction:column;height:100%;overflow:hidden}.publish-control-header{display:flex;align-items:center;justify-content:space-between;padding:var(--space-layout-sm);border-bottom:var(--border-subtle);flex-shrink:0}.publish-control-title{font-size:var(--font-size-h3);font-weight:var(--font-weight-semibold);color:var(--color-text-primary);margin:0}.publish-control-close-button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:transparent;border:none;border-radius:var(--radius-md);color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-all)}.publish-control-close-button:hover{background:var(--color-bg-overlay);color:var(--color-text-primary)}.publish-control-close-button:active{background:var(--color-bg-surface);transform:scale(.95)}.publish-control-content{flex:1;overflow-y:auto;padding:var(--space-layout-sm)}.publish-control-content::-webkit-scrollbar{width:8px}.publish-control-content::-webkit-scrollbar-track{background:var(--color-bg-base)}.publish-control-content::-webkit-scrollbar-thumb{background:var(--color-bg-overlay);border-radius:var(--radius-full)}.publish-control-content::-webkit-scrollbar-thumb:hover{background:var(--color-border-default)}.publish-control__form{display:flex;flex-direction:column;gap:var(--space-component-lg)}.publish-control__field{display:flex;flex-direction:column;gap:var(--gap-sm)}.publish-control__label{font-size:var(--font-size-body-sm);font-weight:var(--font-weight-medium);color:var(--color-text-secondary);line-height:var(--line-height-normal);margin:0}.publish-control__select{width:100%;padding:var(--space-component-sm) var(--space-component-md);padding-right:var(--spacing-8);border-radius:var(--radius-md);font-family:var(--font-family-sans);font-size:var(--font-size-body-sm);line-height:var(--line-height-normal);background:var(--color-bg-elevated);color:var(--color-text-primary);border:var(--border-default);appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2394a3b8' d='M6 9L1 4h10z'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--spacing-3) center;cursor:pointer;transition:var(--transition-colors),var(--transition-shadow)}.publish-control__select:hover:not(:disabled){border-color:var(--color-border-strong)}.publish-control__select:focus{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-glow-primary)}.publish-control__select:disabled{background:var(--color-bg-base);color:var(--color-text-disabled);cursor:not-allowed;opacity:.6}.publish-control__select--error{border-color:var(--color-border-error)}.publish-control__select--error:focus{box-shadow:var(--shadow-glow-error)}.publish-control__input{width:100%;padding:var(--space-component-sm) var(--space-component-md);border-radius:var(--radius-md);font-family:var(--font-family-sans);font-size:var(--font-size-body-sm);line-height:var(--line-height-normal);background:var(--color-bg-elevated);color:var(--color-text-primary);border:var(--border-default);transition:var(--transition-colors),var(--transition-shadow)}.publish-control__input::placeholder{color:var(--color-text-muted)}.publish-control__input:hover:not(:disabled){border-color:var(--color-border-strong)}.publish-control__input:focus{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-glow-primary)}.publish-control__input:disabled{background:var(--color-bg-base);color:var(--color-text-disabled);cursor:not-allowed;opacity:.6}.publish-control__input--error{border-color:var(--color-border-error)}.publish-control__input--error:focus{box-shadow:var(--shadow-glow-error)}.publish-control__textarea{width:100%;padding:var(--space-component-sm) var(--space-component-md);border-radius:var(--radius-md);min-height:180px;font-family:var(--font-family-mono);font-size:var(--font-size-body-sm);line-height:var(--line-height-relaxed);background:var(--color-bg-elevated);color:var(--color-text-primary);border:var(--border-default);resize:vertical;transition:var(--transition-colors),var(--transition-shadow)}.publish-control__textarea::placeholder{color:var(--color-text-muted);font-family:var(--font-family-mono)}.publish-control__textarea:hover:not(:disabled){border-color:var(--color-border-strong)}.publish-control__textarea:focus{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-glow-primary)}.publish-control__textarea:disabled{background:var(--color-bg-base);color:var(--color-text-disabled);cursor:not-allowed;opacity:.6}.publish-control__textarea--error{border-color:var(--color-border-error)}.publish-control__textarea--error:focus{box-shadow:var(--shadow-glow-error)}.publish-control__checkbox-wrapper{display:flex;align-items:center;gap:var(--gap-sm);padding:var(--space-component-sm) 0}.publish-control__checkbox{width:18px;height:18px;accent-color:var(--color-primary-500);cursor:pointer;transition:var(--transition-colors)}.publish-control__checkbox:disabled{cursor:not-allowed;opacity:.5}.publish-control__checkbox:focus-visible{outline:2px solid var(--color-border-focus);outline-offset:2px;border-radius:var(--radius-sm)}.publish-control__checkbox-label{font-size:var(--font-size-body-sm);font-weight:var(--font-weight-regular);color:var(--color-text-secondary);line-height:var(--line-height-normal);cursor:pointer;-webkit-user-select:none;user-select:none;margin:0}.publish-control__checkbox:disabled+.publish-control__checkbox-label{cursor:not-allowed;opacity:.5}.publish-control__submit{width:100%;padding:var(--space-component-sm) var(--space-component-lg);border-radius:var(--radius-md);border:none;font-family:var(--font-family-sans);font-size:var(--font-size-body-sm);font-weight:var(--font-weight-semibold);line-height:var(--line-height-normal);background:var(--color-primary-500);color:var(--color-text-on-primary);box-shadow:var(--shadow-sm);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);-webkit-user-select:none;user-select:none}.publish-control__submit:hover:not(:disabled){background:var(--color-primary-600);box-shadow:var(--shadow-md);transform:translateY(-1px)}.publish-control__submit:active:not(:disabled){background:var(--color-primary-700);box-shadow:var(--shadow-xs);transform:translateY(0)}.publish-control__submit:focus-visible{outline:none;box-shadow:var(--shadow-glow-primary)}.publish-control__submit:disabled{background:var(--color-bg-overlay);color:var(--color-text-disabled);cursor:not-allowed;box-shadow:none;transform:none;opacity:.6}.publish-control__error-text{font-size:var(--font-size-caption);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);color:var(--color-error-light);margin:0;animation:slideDown var(--duration-fast) var(--ease-out)}.publish-control__message{padding:var(--space-component-md);border-radius:var(--radius-md);font-size:var(--font-size-body-sm);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);border:var(--border-width-1) solid;animation:slideDown var(--duration-normal) var(--ease-out)}.publish-control__message--success{background:var(--color-success-bg);color:var(--color-success-light);border-color:var(--color-success-border)}.publish-control__message--error{background:var(--color-error-bg);color:var(--color-error-light);border-color:var(--color-error-border)}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.publish-control__field-hint{font-size:var(--font-size-caption);font-weight:var(--font-weight-regular);color:var(--color-text-tertiary);font-style:italic}.publish-control__hint{font-size:var(--font-size-body-sm);font-weight:var(--font-weight-regular);color:var(--color-text-secondary);line-height:var(--line-height-normal);margin:0;padding:var(--space-component-md);text-align:center;opacity:.7}@media (prefers-reduced-motion: reduce){.publish-control-panel{animation-duration:.01ms!important}.publish-control__submit,.publish-control__select,.publish-control__input,.publish-control__textarea,.publish-control__checkbox,.publish-control__message,.publish-control__error-text,.publish-control-close-button{animation-duration:.01ms!important;transition-duration:.01ms!important}.publish-control__submit:hover:not(:disabled){transform:none}}@media (max-width: 768px){.publish-control-panel{width:100%;left:0}}.settings-panel{position:fixed;top:0;right:0;bottom:0;width:550px;z-index:1000;background:var(--color-glass-bg);-webkit-backdrop-filter:blur(var(--blur-lg));backdrop-filter:blur(var(--blur-lg));border-left:var(--border-default);box-shadow:var(--shadow-xl);animation:slideInRight var(--duration-slow) var(--ease-smooth)}.settings-panel-inner{display:flex;flex-direction:column;height:100%;overflow:hidden}.settings-header{display:flex;align-items:center;justify-content:space-between;padding:var(--space-layout-sm);border-bottom:var(--border-subtle);flex-shrink:0}.settings-title{font-size:var(--font-size-h3);font-weight:var(--font-weight-semibold);color:var(--color-text-primary);margin:0}.settings-close-button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:transparent;border:none;border-radius:var(--radius-md);color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-all)}.settings-close-button:hover{background:var(--color-bg-overlay);color:var(--color-text-primary)}.settings-close-button:active{background:var(--color-bg-surface);transform:scale(.95)}.settings-tabs{display:flex;gap:var(--gap-xs);padding:var(--space-component-md);border-bottom:var(--border-subtle);flex-shrink:0}.settings-tab{display:flex;align-items:center;gap:var(--gap-xs);padding:var(--space-component-sm) var(--space-component-md);background:transparent;border:none;border-radius:var(--radius-md);color:var(--color-text-secondary);font-size:var(--font-size-body-sm);font-weight:var(--font-weight-medium);cursor:pointer;transition:var(--transition-all);position:relative}.settings-tab svg{width:16px;height:16px}.settings-tab:hover{background:var(--color-bg-overlay);color:var(--color-text-primary)}.settings-tab.active{background:var(--color-bg-surface);color:var(--color-primary-500);box-shadow:var(--shadow-sm)}.settings-tab.active:after{content:"";position:absolute;bottom:0;left:50%;transform:translate(-50%);width:40%;height:2px;background:var(--color-primary-500);border-radius:var(--radius-full)}.settings-content{flex:1;overflow-y:auto;padding:var(--space-layout-sm)}.settings-content::-webkit-scrollbar{width:8px}.settings-content::-webkit-scrollbar-track{background:var(--color-bg-base)}.settings-content::-webkit-scrollbar-thumb{background:var(--color-bg-overlay);border-radius:var(--radius-full)}.settings-content::-webkit-scrollbar-thumb:hover{background:var(--color-border-default)}.settings-footer{display:flex;align-items:center;justify-content:space-between;padding:var(--space-component-md);border-top:var(--border-subtle);flex-shrink:0}.settings-footer-left{display:flex;align-items:center}.settings-reset-button{padding:var(--space-component-sm) var(--space-component-md);background:transparent;border:var(--border-default);border-radius:var(--radius-md);color:var(--color-text-secondary);font-size:var(--font-size-body-sm);font-weight:var(--font-weight-medium);cursor:pointer;transition:var(--transition-all)}.settings-reset-button:hover{background:var(--color-bg-overlay);border-color:var(--color-border-strong);color:var(--color-text-primary)}.settings-reset-button:active{background:var(--color-bg-surface);transform:scale(.98)}.settings-section{margin-bottom:var(--space-layout-md)}.settings-section:last-child{margin-bottom:0}.settings-section-title{font-size:var(--font-size-body-md);font-weight:var(--font-weight-semibold);color:var(--color-text-primary);margin:0 0 var(--space-component-md) 0;padding-bottom:var(--space-component-sm);border-bottom:var(--border-subtle)}.settings-field{display:flex;flex-direction:column;gap:var(--gap-xs);margin-bottom:var(--space-component-lg)}.settings-label{font-size:var(--font-size-body-sm);font-weight:var(--font-weight-medium);color:var(--color-text-secondary)}.settings-description{font-size:var(--font-size-caption);color:var(--color-text-tertiary);margin:0}.settings-select,.settings-input{width:100%;padding:var(--space-component-sm) var(--space-component-md);background:var(--color-bg-elevated);border:var(--border-default);border-radius:var(--radius-md);color:var(--color-text-primary);font-size:var(--font-size-body-sm);font-family:var(--font-family-sans);transition:var(--transition-all)}.settings-select:hover,.settings-input:hover{border-color:var(--color-border-strong)}.settings-select:focus,.settings-input:focus{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-glow-primary)}.settings-checkbox-wrapper{display:flex;align-items:center;gap:var(--gap-sm);padding:var(--space-component-sm) 0}.settings-checkbox{width:18px;height:18px;accent-color:var(--color-primary-500);cursor:pointer}.settings-checkbox-label{font-size:var(--font-size-body-sm);color:var(--color-text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}@keyframes slideInRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@media (prefers-reduced-motion: reduce){.settings-panel{animation-duration:.01ms!important}.settings-tab,.settings-close-button,.settings-reset-button{transition-duration:.01ms!important}}@media (max-width: 768px){.settings-panel{width:100%;left:0}}.keyboard-shortcuts-overlay{position:fixed;inset:0;background:var(--color-overlay);backdrop-filter:blur(var(--blur-sm));-webkit-backdrop-filter:blur(var(--blur-sm));display:flex;align-items:center;justify-content:center;z-index:1000;animation:fadeIn var(--duration-normal) var(--ease-smooth)}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.keyboard-shortcuts-dialog{background:var(--color-bg-surface);border:var(--border-default);border-radius:var(--radius-lg);box-shadow:var(--shadow-xl);max-width:600px;width:90%;max-height:80vh;display:flex;flex-direction:column;animation:slideInUp var(--duration-normal) var(--ease-smooth)}@keyframes slideInUp{0%{opacity:0;transform:translateY(20px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.keyboard-shortcuts-header{display:flex;justify-content:space-between;align-items:center;padding:var(--space-layout-sm) var(--space-layout-md);border-bottom:var(--border-subtle)}.keyboard-shortcuts-title{margin:0;font-size:var(--font-size-h4);font-weight:var(--font-weight-semibold);color:var(--color-text-primary);letter-spacing:var(--letter-spacing-tight)}.keyboard-shortcuts-close{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:transparent;color:var(--color-text-tertiary);border:none;border-radius:var(--radius-md);cursor:pointer;transition:var(--transition-colors),var(--transition-transform)}.keyboard-shortcuts-close:hover{background:var(--color-bg-overlay);color:var(--color-text-secondary)}.keyboard-shortcuts-close:active{transform:scale(.95)}.keyboard-shortcuts-close:focus-visible{outline:none;box-shadow:var(--shadow-glow-primary)}.keyboard-shortcuts-content{flex:1;overflow-y:auto;padding:var(--space-layout-md)}.keyboard-shortcuts-category{margin-bottom:var(--space-layout-lg)}.keyboard-shortcuts-category:last-child{margin-bottom:0}.keyboard-shortcuts-category-title{margin:0 0 var(--space-component-md) 0;font-size:var(--font-size-body-sm);font-weight:var(--font-weight-semibold);color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:var(--letter-spacing-wide)}.keyboard-shortcuts-list{display:flex;flex-direction:column;gap:var(--gap-sm)}.keyboard-shortcut-item{display:flex;justify-content:space-between;align-items:center;padding:var(--space-component-sm) var(--space-component-md);background:var(--color-bg-elevated);border:var(--border-subtle);border-radius:var(--radius-md);transition:var(--transition-colors)}.keyboard-shortcut-item:hover{background:var(--color-bg-overlay);border-color:var(--color-border-strong)}.keyboard-shortcut-keys{display:flex;align-items:center;gap:var(--gap-xs)}.keyboard-key{display:inline-flex;align-items:center;justify-content:center;min-width:28px;padding:var(--spacing-1) var(--spacing-2);background:var(--color-bg-base);color:var(--color-text-primary);border:var(--border-default);border-radius:var(--radius-sm);font-family:var(--font-family-mono);font-size:var(--font-size-body-sm);font-weight:var(--font-weight-medium);box-shadow:var(--shadow-xs),inset 0 -2px 0 0 var(--color-border-default);line-height:1;white-space:nowrap}.keyboard-key-separator{color:var(--color-text-tertiary);font-size:var(--font-size-caption);font-weight:var(--font-weight-medium)}.keyboard-shortcut-description{color:var(--color-text-secondary);font-size:var(--font-size-body-sm);text-align:right}.keyboard-shortcuts-footer{padding:var(--space-component-md) var(--space-layout-md);border-top:var(--border-subtle);background:var(--color-bg-elevated)}.keyboard-shortcuts-hint{margin:0;text-align:center;color:var(--color-text-tertiary);font-size:var(--font-size-caption)}.keyboard-shortcuts-content::-webkit-scrollbar{width:8px}.keyboard-shortcuts-content::-webkit-scrollbar-track{background:var(--color-bg-elevated)}.keyboard-shortcuts-content::-webkit-scrollbar-thumb{background:var(--color-border-default);border-radius:var(--radius-full);transition:var(--transition-colors)}.keyboard-shortcuts-content::-webkit-scrollbar-thumb:hover{background:var(--color-border-strong)}@media (max-width: 768px){.keyboard-shortcuts-dialog{max-width:95%;max-height:90vh}.keyboard-shortcut-item{flex-direction:column;align-items:flex-start;gap:var(--gap-sm)}.keyboard-shortcut-description{text-align:left}}@media (prefers-reduced-motion: reduce){.keyboard-shortcuts-overlay,.keyboard-shortcuts-dialog{animation:none}.keyboard-shortcuts-close{transition:none}}._connectionBadge_kl6ey_1{display:flex;align-items:center;gap:var(--gap-sm);padding:var(--spacing-1-5) var(--spacing-3);border-radius:var(--radius-full);font-size:var(--font-size-caption);font-weight:var(--font-weight-medium);box-shadow:var(--shadow-xs);transition:var(--transition-all);cursor:default}._connectionBadge_kl6ey_1._hasError_kl6ey_27{cursor:help}._connectionBadge_kl6ey_1._connected_kl6ey_37{background-color:var(--color-success-bg);color:var(--color-success-dark);border:var(--border-width-1) solid var(--color-success-border)}._connectionBadge_kl6ey_1._connecting_kl6ey_49,._connectionBadge_kl6ey_1._reconnecting_kl6ey_51{background-color:var(--color-warning-bg);color:var(--color-warning-dark);border:var(--border-width-1) solid var(--color-warning-border)}._connectionBadge_kl6ey_1._disconnected_kl6ey_63{background-color:var(--color-error-bg);color:var(--color-error-dark);border:var(--border-width-1) solid var(--color-error-border)}._statusIndicator_kl6ey_77{width:8px;height:8px;border-radius:var(--radius-circle);transition:var(--transition-opacity)}._statusIndicator_kl6ey_77._connected_kl6ey_37{background-color:var(--color-success)}._statusIndicator_kl6ey_77._connecting_kl6ey_49,._statusIndicator_kl6ey_77._reconnecting_kl6ey_51{background-color:var(--color-warning);animation:_statusPulse_kl6ey_1 2s var(--ease-smooth) infinite}._statusIndicator_kl6ey_77._disconnected_kl6ey_63{background-color:var(--color-error)}._statusText_kl6ey_121{line-height:var(--line-height-snug);letter-spacing:var(--letter-spacing-normal)}@keyframes _statusPulse_kl6ey_1{0%,to{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(.95)}}@media (prefers-reduced-motion: reduce){._statusIndicator_kl6ey_77._connecting_kl6ey_49,._statusIndicator_kl6ey_77._reconnecting_kl6ey_51{animation:none}._connectionBadge_kl6ey_1{transition:none}}.dashboard-layout{width:100vw;height:100vh;display:flex;flex-direction:column;background:var(--color-bg-base);overflow:hidden}.dashboard-header{display:flex;justify-content:space-between;align-items:center;gap:var(--space-layout-md);padding:var(--space-component-md) var(--space-layout-sm);background:var(--color-bg-surface);border-bottom:var(--border-subtle);box-shadow:var(--shadow-sm);z-index:100}.filter-pills-bar{position:relative;padding:var(--spacing-1-5) var(--space-layout-md);background:color-mix(in srgb,var(--color-bg-overlay) 65%,transparent);border-bottom:var(--border-subtle);-webkit-backdrop-filter:blur(var(--blur-sm));backdrop-filter:blur(var(--blur-sm));min-height:0;display:flex;align-items:center;gap:var(--gap-md);z-index:90}.dashboard-title{margin:0;font-size:var(--font-size-h3);font-weight:var(--font-weight-semibold);color:var(--color-text-primary);letter-spacing:var(--letter-spacing-tight);white-space:nowrap}.view-toggle-container{display:flex;align-items:center;gap:var(--gap-md);flex:1;justify-content:center}.view-toggle-label{font-size:var(--font-size-body-sm);font-weight:var(--font-weight-medium);color:var(--color-text-tertiary);letter-spacing:var(--letter-spacing-wide);text-transform:uppercase;font-size:var(--font-size-caption)}.view-toggle-group{display:inline-flex;background:var(--color-bg-elevated);padding:var(--spacing-1);border-radius:var(--radius-full);border:var(--border-subtle);box-shadow:var(--shadow-inner);gap:var(--gap-xs)}.view-toggle-button{position:relative;padding:var(--space-component-sm) var(--space-component-lg);background:transparent;color:var(--color-text-tertiary);border:none;border-radius:var(--radius-full);font-family:var(--font-family-sans);font-size:var(--font-size-body-sm);font-weight:var(--font-weight-medium);cursor:pointer;transition:var(--transition-colors),var(--transition-transform);white-space:nowrap}.view-toggle-button:hover:not(.active){color:var(--color-text-secondary);background:var(--color-bg-overlay)}.view-toggle-button.active{background:var(--color-primary-500);color:var(--color-text-on-primary);box-shadow:var(--shadow-sm)}.view-toggle-button:active{transform:scale(.98)}.view-toggle-button:focus-visible{outline:none;box-shadow:var(--shadow-glow-primary)}.dashboard-actions{display:flex;align-items:center;gap:var(--gap-md)}.icon-button{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:var(--spacing-2);background:transparent;color:var(--color-text-tertiary);border:none;border-radius:var(--radius-md);cursor:pointer;transition:var(--transition-colors),var(--transition-transform)}.icon-button:hover{background:var(--color-bg-overlay);color:var(--color-text-secondary)}.icon-button:active{transform:scale(.95)}.icon-button:focus-visible{outline:none;box-shadow:var(--shadow-glow-primary)}.help-button:hover{color:var(--color-primary-500);background:var(--color-primary-50)}.help-button:focus-visible{box-shadow:var(--shadow-glow-primary)}.clear-button:hover{color:var(--color-error);background:var(--color-error-bg)}.clear-button:focus-visible{box-shadow:var(--shadow-glow-error)}.controls-toggle{display:inline-flex;align-items:center;gap:var(--gap-sm);padding:var(--space-component-sm) var(--space-component-md);background:var(--color-bg-elevated);color:var(--color-text-secondary);border:var(--border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);font-size:var(--font-size-body-sm);font-weight:var(--font-weight-medium);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow),var(--transition-transform);white-space:nowrap}.controls-toggle.primary{background:var(--color-primary-500);color:var(--color-text-on-primary);border-color:var(--color-primary-500);box-shadow:var(--shadow-md);font-weight:var(--font-weight-semibold)}.controls-toggle.primary:hover{background:var(--color-primary-600);border-color:var(--color-primary-600);box-shadow:var(--shadow-lg)}.controls-toggle.primary.active{background:var(--color-primary-700);border-color:var(--color-primary-700)}.controls-toggle:hover{background:var(--color-bg-surface);color:var(--color-text-primary);border-color:var(--color-border-strong);box-shadow:var(--shadow-sm)}.controls-toggle.active{background:var(--color-success);color:var(--color-text-on-primary);border-color:var(--color-success);box-shadow:var(--shadow-sm)}.controls-toggle.active:hover{background:var(--color-success-dark);border-color:var(--color-success-dark)}.controls-toggle:active{transform:scale(.98)}.controls-toggle:focus-visible{outline:none;box-shadow:var(--shadow-glow-primary)}.controls-toggle.active:focus-visible{box-shadow:var(--shadow-glow-success)}.controls-toggle svg{width:16px;height:16px;flex-shrink:0;transition:var(--transition-transform)}.controls-toggle.active svg{transform:rotate(45deg)}.dashboard-main{flex:1;display:flex;overflow:hidden;position:relative}.graph-container{flex:1;overflow:hidden;position:relative}.controls-sidebar{width:400px;background:var(--color-glass-bg);backdrop-filter:blur(var(--blur-lg));-webkit-backdrop-filter:blur(var(--blur-lg));border-left:var(--border-subtle);box-shadow:var(--shadow-lg);overflow-y:auto;animation:slideInRight var(--duration-slow) var(--ease-smooth)}@keyframes slideInRight{0%{opacity:0;transform:translate(20px)}to{opacity:1;transform:translate(0)}}.controls-sidebar-inner{padding:var(--space-layout-sm)}.controls-title{margin:0 0 var(--space-layout-sm) 0;font-size:var(--font-size-h4);font-weight:var(--font-weight-semibold);color:var(--color-text-primary);letter-spacing:var(--letter-spacing-tight)}.control-section{margin-bottom:var(--space-layout-md)}.control-section-title{margin:0 0 var(--space-component-md) 0;font-size:var(--font-size-h5);font-weight:var(--font-weight-medium);color:var(--color-text-secondary)}.controls-sidebar::-webkit-scrollbar{width:8px}.controls-sidebar::-webkit-scrollbar-track{background:var(--color-bg-elevated)}.controls-sidebar::-webkit-scrollbar-thumb{background:var(--color-border-default);border-radius:var(--radius-full);transition:var(--transition-colors)}.controls-sidebar::-webkit-scrollbar-thumb:hover{background:var(--color-border-strong)}@media (max-width: 1024px){.dashboard-header{flex-wrap:wrap;gap:var(--gap-md)}.view-toggle-container{order:3;width:100%;justify-content:center}.controls-sidebar{width:320px}}@media (max-width: 768px){.dashboard-title{font-size:var(--font-size-h4)}.view-toggle-button{padding:var(--spacing-2) var(--spacing-4);font-size:var(--font-size-caption)}.controls-toggle span{display:none}.controls-sidebar{width:280px}}@media (prefers-reduced-motion: reduce){.controls-sidebar{animation:none}.view-toggle-button,.icon-button,.controls-toggle{transition:none}.controls-toggle svg{transition:none}}@media print{.dashboard-header,.controls-sidebar{display:none}.dashboard-main{flex:1}}._container_z8335_5{display:flex;align-items:center;justify-content:center;min-height:400px;padding:var(--space-layout-md);background:var(--color-bg-base)}._content_z8335_23{max-width:500px;text-align:center;padding:var(--space-layout-lg);background:var(--color-bg-surface);border:var(--border-subtle);border-radius:var(--radius-xl);box-shadow:var(--shadow-lg)}._icon_z8335_43{color:var(--color-error);margin-bottom:var(--spacing-6);animation:_shake_z8335_1 .5s var(--ease-smooth)}._title_z8335_55{font-size:var(--font-size-h2);font-weight:var(--font-weight-bold);color:var(--color-text-primary);margin:0 0 var(--spacing-4) 0;line-height:var(--line-height-tight)}._description_z8335_71{font-size:var(--font-size-body);color:var(--color-text-secondary);line-height:var(--line-height-relaxed);margin:0 0 var(--spacing-6) 0}._details_z8335_85{margin:var(--spacing-6) 0;text-align:left;background:var(--color-bg-base);border:var(--border-default);border-radius:var(--radius-md);padding:var(--space-component-md)}._summary_z8335_103{font-size:var(--font-size-body-sm);font-weight:var(--font-weight-semibold);color:var(--color-text-secondary);cursor:pointer;-webkit-user-select:none;user-select:none;padding:var(--spacing-2);margin:calc(var(--space-component-md) * -1);margin-bottom:var(--spacing-3)}._summary_z8335_103:hover{color:var(--color-text-primary)}._errorMessage_z8335_133{font-size:var(--font-size-body-sm);color:var(--color-error-light);margin-bottom:var(--spacing-3);line-height:var(--line-height-relaxed)}._stackTrace_z8335_147{font-family:var(--font-family-mono);font-size:var(--font-size-caption);color:var(--color-text-tertiary);background:var(--color-bg-elevated);padding:var(--space-component-sm);border-radius:var(--radius-sm);overflow-x:auto;white-space:pre-wrap;word-break:break-word;max-height:200px;overflow-y:auto}._actions_z8335_175{display:flex;gap:var(--gap-md);justify-content:center}._primaryButton_z8335_187{padding:var(--space-component-sm) var(--space-component-lg);font-size:var(--font-size-body-sm);font-weight:var(--font-weight-semibold);color:var(--color-text-on-primary);background:var(--color-primary-500);border:none;border-radius:var(--radius-md);cursor:pointer;box-shadow:var(--shadow-sm);transition:var(--transition-colors),var(--transition-shadow)}._primaryButton_z8335_187:hover{background:var(--color-primary-600);box-shadow:var(--shadow-md)}._primaryButton_z8335_187:active{background:var(--color-primary-700);box-shadow:var(--shadow-xs);transform:translateY(1px)}._primaryButton_z8335_187:focus-visible{outline:none;box-shadow:var(--shadow-glow-primary)}._secondaryButton_z8335_245{padding:var(--space-component-sm) var(--space-component-lg);font-size:var(--font-size-body-sm);font-weight:var(--font-weight-semibold);color:var(--color-text-secondary);background:transparent;border:var(--border-default);border-radius:var(--radius-md);cursor:pointer;transition:var(--transition-colors)}._secondaryButton_z8335_245:hover{background:var(--color-bg-overlay);color:var(--color-text-primary);border-color:var(--color-border-strong)}._secondaryButton_z8335_245:active{transform:translateY(1px)}._secondaryButton_z8335_245:focus-visible{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-glow-primary)}@keyframes _shake_z8335_1{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-4px)}20%,40%,60%,80%{transform:translate(4px)}}@media (prefers-reduced-motion: reduce){._icon_z8335_43{animation:none}}._container_1vp06_1{display:flex;flex-direction:column;gap:var(--space-layout-sm);height:100%;padding:var(--space-layout-sm);background:var(--color-bg-surface)}._header_1vp06_19{display:flex;align-items:center;justify-content:space-between;gap:var(--gap-sm)}._metrics_1vp06_33{display:flex;gap:var(--gap-lg);flex-wrap:wrap}._metricLabel_1vp06_45{display:block;font-size:var(--font-size-overline);color:var(--color-text-tertiary);text-transform:uppercase;letter-spacing:var(--letter-spacing-wider)}._metricValue_1vp06_61{font-size:var(--font-size-body-md);font-weight:var(--font-weight-semibold);color:var(--color-text-primary)}._actions_1vp06_73{display:flex;gap:var(--gap-sm)}._actions_1vp06_73 button{padding:var(--spacing-1) var(--spacing-3);border-radius:var(--radius-sm);border:none;cursor:pointer;background:#6366f140;color:var(--color-text-primary);transition:background-color var(--duration-fast) ease}._actions_1vp06_73 button:disabled{opacity:.5;cursor:not-allowed}._actions_1vp06_73 button:hover:not(:disabled){background:#6366f173}._tableContainer_1vp06_121{display:flex;flex-direction:column;background:#0f172a99;border:1px solid rgba(148,163,184,.1);border-radius:var(--radius-md);overflow:hidden;flex:2 1 0;min-height:0}._contentArea_1vp06_143{display:flex;gap:var(--space-layout-sm);flex:1;min-height:0}._detailPanel_1vp06_157{flex:1 1 0;background:#0f172a80;border:1px solid rgba(148,163,184,.15);border-radius:var(--radius-md);padding:var(--spacing-3);display:flex;flex-direction:column;gap:var(--gap-md);max-height:100%;overflow-y:auto}._headerRow_1vp06_183,._dataRow_1vp06_185{display:grid;grid-template-columns:200px 140px 160px 180px 160px 120px 100px;gap:var(--gap-sm);padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-body-xs);align-items:center}._headerRow_1vp06_183{background:#94a3b81a;font-weight:var(--font-weight-semibold);text-transform:uppercase;letter-spacing:var(--letter-spacing-wide)}._dataRow_1vp06_185{border-bottom:1px solid rgba(148,163,184,.08)}._virtualViewport_1vp06_225{overflow-y:auto}._dataRowStripe_1vp06_233{background:#94a3b80d}._dataRow_1vp06_185{cursor:pointer;transition:background-color var(--duration-fast) ease}._dataRow_1vp06_185:focus-visible{outline:2px solid var(--color-primary-400);outline-offset:2px}._dataRowSelected_1vp06_261{background:#6366f140;border-left:3px solid var(--color-primary-400)}._dataRowSelected_1vp06_261 span{color:var(--color-text-primary)}._emptyState_1vp06_279,._loading_1vp06_281,._error_1vp06_283{padding:var(--spacing-4);text-align:center;color:var(--color-text-secondary)}._error_1vp06_283{color:var(--color-error)}._retentionBanner_1vp06_303{display:flex;flex-direction:column;gap:var(--gap-xs);background:#94a3b814;border:1px solid rgba(148,163,184,.15);border-radius:var(--radius-sm);padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-body-xs);color:var(--color-text-secondary)}._retentionBanner_1vp06_303 strong{color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}@media (max-width: 1280px){._contentArea_1vp06_143{flex-direction:column}._detailPanel_1vp06_157{max-height:none}}._detailHeader_1vp06_357{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--gap-sm)}._detailHeader_1vp06_357 h3{margin:0;font-size:var(--font-size-body-lg);color:var(--color-text-primary)}._detailHeader_1vp06_357 p{margin:0;font-size:var(--font-size-body-xs);color:var(--color-text-secondary)}._detailHeader_1vp06_357 button{padding:var(--spacing-1) var(--spacing-3);border-radius:var(--radius-sm);border:none;cursor:pointer;background:#6366f133;color:var(--color-primary-50);font-size:var(--font-size-body-xs);text-transform:uppercase;letter-spacing:var(--letter-spacing-wide)}._detailHeader_1vp06_357 button:hover{background:#6366f159}._detailSection_1vp06_427{display:flex;flex-direction:column;gap:var(--gap-sm)}._detailSection_1vp06_427 h4{margin:0;font-size:var(--font-size-body-sm);color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:var(--letter-spacing-wide)}._detailList_1vp06_455{display:grid;grid-template-columns:minmax(110px,.45fr) 1fr;gap:var(--gap-xs) var(--gap-sm);font-size:var(--font-size-body-xs)}._detailList_1vp06_455 dt{color:var(--color-text-tertiary);font-weight:var(--font-weight-semibold)}._detailList_1vp06_455 dd{margin:0;color:var(--color-text-primary);word-break:break-word}._consumptionList_1vp06_491{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:var(--gap-xs)}._consumptionList_1vp06_491 li{display:flex;flex-direction:column;gap:2px;padding:var(--spacing-2);border:1px solid rgba(148,163,184,.18);border-radius:var(--radius-sm);background:#1e293b8c}._consumerName_1vp06_529{font-weight:var(--font-weight-semibold);color:var(--color-text-primary)}._runBadge_1vp06_539{display:inline-flex;align-items:center;justify-content:center;align-self:flex-start;padding:2px 6px;border-radius:var(--radius-xs);font-size:var(--font-size-caption);background:#6366f140;color:var(--color-primary-100);margin-top:2px}._emptyDetail_1vp06_565,._emptyConsumption_1vp06_567{font-size:var(--font-size-body-sm);color:var(--color-text-secondary);margin:0}:root{--color-bg-base: #0a0a0b;--color-bg-elevated: #121214;--color-bg-surface: #1a1a1e;--color-bg-overlay: #232329;--color-bg-float: #2a2a32;--color-primary-50: #eef2ff;--color-primary-100: #e0e7ff;--color-primary-200: #c7d2fe;--color-primary-300: #a5b4fc;--color-primary-400: #818cf8;--color-primary-500: #6366f1;--color-primary-600: #4f46e5;--color-primary-700: #4338ca;--color-primary-800: #3730a3;--color-primary-900: #312e81;--color-secondary-50: #fdf4ff;--color-secondary-100: #fae8ff;--color-secondary-200: #f5d0fe;--color-secondary-300: #f0abfc;--color-secondary-400: #e879f9;--color-secondary-500: #d946ef;--color-secondary-600: #c026d3;--color-secondary-700: #a21caf;--color-secondary-800: #86198f;--color-secondary-900: #701a75;--color-tertiary-50: #ecfeff;--color-tertiary-100: #cffafe;--color-tertiary-200: #a5f3fc;--color-tertiary-300: #67e8f9;--color-tertiary-400: #22d3ee;--color-tertiary-500: #06b6d4;--color-tertiary-600: #0891b2;--color-tertiary-700: #0e7490;--color-tertiary-800: #155e75;--color-tertiary-900: #164e63;--color-success-light: #6ee7b7;--color-success: #10b981;--color-success-dark: #047857;--color-success-bg: rgba(16, 185, 129, .1);--color-success-border: rgba(16, 185, 129, .3);--color-warning-light: #fbbf24;--color-warning: #f59e0b;--color-warning-dark: #d97706;--color-warning-bg: rgba(245, 158, 11, .1);--color-warning-border: rgba(245, 158, 11, .3);--color-error-light: #f87171;--color-error: #ef4444;--color-error-dark: #dc2626;--color-error-bg: rgba(239, 68, 68, .1);--color-error-border: rgba(239, 68, 68, .3);--color-info-light: #60a5fa;--color-info: #3b82f6;--color-info-dark: #2563eb;--color-info-bg: rgba(59, 130, 246, .1);--color-info-border: rgba(59, 130, 246, .3);--color-active-light: #818cf8;--color-active: #6366f1;--color-active-dark: #4f46e5;--color-active-bg: rgba(99, 102, 241, .1);--color-active-border: rgba(99, 102, 241, .3);--color-idle-light: #94a3b8;--color-idle: #64748b;--color-idle-dark: #475569;--color-idle-bg: rgba(100, 116, 139, .1);--color-idle-border: rgba(100, 116, 139, .3);--color-text-primary: #f8fafc;--color-text-secondary: #cbd5e1;--color-text-tertiary: #94a3b8;--color-text-muted: #64748b;--color-text-disabled: #475569;--color-text-on-primary: #ffffff;--color-text-on-dark: #0f172a;--color-border-subtle: #1e293b;--color-border-default: #334155;--color-border-strong: #475569;--color-border-focus: #6366f1;--color-border-error: #ef4444;--color-divider: rgba(148, 163, 184, .1);--color-node-agent-bg: #1e293b;--color-node-agent-border: #3b82f6;--color-node-agent-border-selected: #6366f1;--color-node-agent-text: #f8fafc;--color-node-agent-badge: #334155;--color-node-agent-badge-text: #94a3b8;--color-node-message-bg: #422006;--color-node-message-border: #f59e0b;--color-node-message-border-selected: #d946ef;--color-node-message-text: #fef3c7;--color-node-message-metadata: #a16207;--color-edge-default: #475569;--color-edge-active: #6366f1;--color-edge-message: #f59e0b;--color-edge-error: #ef4444;--color-edge-label-bg: rgba(26, 26, 30, .95);--color-edge-label-text: #cbd5e1;--color-glass-bg: rgba(26, 26, 30, .8);--color-glass-border: rgba(148, 163, 184, .1);--color-overlay-backdrop: rgba(10, 10, 11, .7);--color-modal-backdrop: rgba(10, 10, 11, .85);--font-family-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif;--font-family-mono: "JetBrains Mono", "Fira Code", "Consolas", "Monaco", "Courier New", monospace;--font-family-display: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;--font-size-display-2xl: 72px;--font-size-display-xl: 60px;--font-size-display-lg: 48px;--font-size-display-md: 36px;--font-size-h1: 32px;--font-size-h2: 24px;--font-size-h3: 20px;--font-size-h4: 18px;--font-size-h5: 16px;--font-size-h6: 14px;--font-size-body-xl: 20px;--font-size-body-lg: 18px;--font-size-body: 16px;--font-size-body-sm: 14px;--font-size-body-xs: 12px;--font-size-caption: 12px;--font-size-overline: 10px;--font-size-tiny: 10px;--font-weight-light: 300;--font-weight-regular: 400;--font-weight-medium: 500;--font-weight-semibold: 600;--font-weight-bold: 700;--line-height-tight: 1.1;--line-height-snug: 1.375;--line-height-normal: 1.5;--line-height-relaxed: 1.625;--line-height-loose: 2;--letter-spacing-tight: -.02em;--letter-spacing-normal: 0;--letter-spacing-wide: .025em;--letter-spacing-wider: .05em;--letter-spacing-widest: .1em;--spacing-0: 0;--spacing-0-5: 2px;--spacing-1: 4px;--spacing-1-5: 6px;--spacing-2: 8px;--spacing-3: 12px;--spacing-4: 16px;--spacing-5: 20px;--spacing-6: 24px;--spacing-8: 32px;--spacing-10: 40px;--spacing-12: 48px;--spacing-16: 64px;--spacing-20: 80px;--spacing-24: 96px;--spacing-32: 128px;--spacing-40: 160px;--spacing-48: 192px;--spacing-56: 224px;--spacing-64: 256px;--space-component-xs: var(--spacing-2);--space-component-sm: var(--spacing-3);--space-component-md: var(--spacing-4);--space-component-lg: var(--spacing-6);--space-component-xl: var(--spacing-8);--space-layout-xs: var(--spacing-4);--space-layout-sm: var(--spacing-6);--space-layout-md: var(--spacing-8);--space-layout-lg: var(--spacing-12);--space-layout-xl: var(--spacing-16);--space-layout-2xl: var(--spacing-24);--gap-xs: var(--spacing-1);--gap-sm: var(--spacing-2);--gap-md: var(--spacing-3);--gap-lg: var(--spacing-4);--gap-xl: var(--spacing-6);--shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, .4);--shadow-sm: 0 2px 4px -1px rgba(0, 0, 0, .5), 0 1px 2px -1px rgba(0, 0, 0, .3);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .6), 0 2px 4px -1px rgba(0, 0, 0, .4);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .7), 0 4px 6px -2px rgba(0, 0, 0, .5);--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, .8), 0 10px 10px -5px rgba(0, 0, 0, .6);--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, .9);--shadow-glow-primary: 0 0 0 3px rgba(99, 102, 241, .3);--shadow-glow-secondary: 0 0 0 3px rgba(217, 70, 239, .3);--shadow-glow-success: 0 0 0 3px rgba(16, 185, 129, .3);--shadow-glow-error: 0 0 0 3px rgba(239, 68, 68, .3);--shadow-glow-warning: 0 0 0 3px rgba(245, 158, 11, .3);--shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, .5);--shadow-inner-lg: inset 0 4px 8px 0 rgba(0, 0, 0, .6);--border-width-0: 0;--border-width-1: 1px;--border-width-2: 2px;--border-width-3: 3px;--border-width-4: 4px;--radius-none: 0;--radius-sm: 4px;--radius-md: 6px;--radius-lg: 8px;--radius-xl: 12px;--radius-2xl: 16px;--radius-3xl: 24px;--radius-full: 9999px;--radius-circle: 50%;--border-subtle: var(--border-width-1) solid var(--color-border-subtle);--border-default: var(--border-width-1) solid var(--color-border-default);--border-strong: var(--border-width-2) solid var(--color-border-strong);--border-focus: var(--border-width-2) solid var(--color-border-focus);--border-error: var(--border-width-2) solid var(--color-border-error);--duration-instant: 0ms;--duration-fast: .1s;--duration-normal: .2s;--duration-slow: .3s;--duration-slower: .4s;--duration-slowest: .5s;--ease-linear: linear;--ease-in: cubic-bezier(.4, 0, 1, 1);--ease-out: cubic-bezier(0, 0, .2, 1);--ease-in-out: cubic-bezier(.4, 0, .2, 1);--ease-smooth: cubic-bezier(.4, 0, .6, 1);--ease-bounce: cubic-bezier(.68, -.55, .265, 1.55);--ease-elastic: cubic-bezier(.175, .885, .32, 1.275);--ease-sharp: cubic-bezier(.4, 0, .6, 1);--transition-colors: color var(--duration-fast) var(--ease-smooth), background-color var(--duration-fast) var(--ease-smooth), border-color var(--duration-fast) var(--ease-smooth);--transition-opacity: opacity var(--duration-normal) var(--ease-out);--transition-transform: transform var(--duration-normal) var(--ease-smooth);--transition-shadow: box-shadow var(--duration-normal) var(--ease-out);--transition-all: all var(--duration-normal) var(--ease-smooth);--transition-base: var(--duration-normal) var(--ease-smooth);--blur-sm: 4px;--blur-md: 8px;--blur-lg: 12px;--blur-xl: 16px;--blur-2xl: 24px}*{margin:0;padding:0;box-sizing:border-box}html{font-size:16px}body{font-family:var(--font-family-sans);font-size:var(--font-size-body);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);color:var(--color-text-primary);background:var(--color-bg-base);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}h1,h2,h3,h4,h5,h6{margin:0;font-weight:var(--font-weight-semibold);color:var(--color-text-primary)}h1{font-size:var(--font-size-h1);font-weight:var(--font-weight-bold);line-height:var(--line-height-tight);letter-spacing:var(--letter-spacing-tight)}h2{font-size:var(--font-size-h2);line-height:var(--line-height-tight);letter-spacing:var(--letter-spacing-tight)}h3{font-size:var(--font-size-h3);line-height:var(--line-height-snug)}h4{font-size:var(--font-size-h4);font-weight:var(--font-weight-medium);line-height:var(--line-height-snug)}h5,h6{font-size:var(--font-size-h5);font-weight:var(--font-weight-medium);line-height:var(--line-height-normal);color:var(--color-text-secondary)}code,pre{font-family:var(--font-family-mono);font-size:.9em;line-height:var(--line-height-relaxed)}button{font-family:inherit;cursor:pointer}#root{width:100vw;height:100vh;overflow:hidden}@keyframes pulse{0%,to{opacity:1}50%{opacity:.6}}.react-flow__controls{background:var(--color-bg-surface)!important;border:1px solid var(--color-border-default)!important}.react-flow__controls-button{background:var(--color-bg-overlay)!important;border:none!important;border-bottom:1px solid var(--color-border-subtle)!important;color:var(--color-text-primary)!important;transition:var(--transition-all)!important;width:32px!important;height:32px!important}.react-flow__controls-button:hover{background:var(--color-primary-500)!important;color:#fff!important}.react-flow__controls-button svg{fill:currentColor!important;width:18px!important;height:18px!important}@media (prefers-reduced-motion: reduce){*{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}*::-webkit-scrollbar{width:10px;height:10px}*::-webkit-scrollbar-track{background:var(--color-bg-base);border-radius:var(--radius-sm, 4px)}*::-webkit-scrollbar-thumb{background:var(--color-bg-overlay);border-radius:var(--radius-sm, 4px);border:2px solid var(--color-bg-base)}*::-webkit-scrollbar-thumb:hover{background:var(--color-border-default)}*::-webkit-scrollbar-thumb:active{background:var(--color-border-strong)}*,div[style*="overflow: auto"],div[style*="overflow-y: auto"],div[style*="overflow-x: auto"],.settings-content,.publish-content{scrollbar-width:thin;scrollbar-color:var(--color-bg-overlay) var(--color-bg-base)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>🦆🐓 Flock 🐤🐧</title>
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-DFRnI_mt.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-fPLNdmp1.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
flock/dashboard/websocket.py
CHANGED
|
@@ -57,9 +57,9 @@ class WebSocketManager:
|
|
|
57
57
|
self._heartbeat_task: asyncio.Task | None = None
|
|
58
58
|
self._shutdown = False
|
|
59
59
|
|
|
60
|
-
# Store streaming output events by agent_name for history (max
|
|
60
|
+
# Store streaming output events by agent_name for history (max 128344 per agent)
|
|
61
61
|
self._streaming_history: dict[str, deque[StreamingOutputEvent]] = defaultdict(
|
|
62
|
-
lambda: deque(maxlen=
|
|
62
|
+
lambda: deque(maxlen=128344)
|
|
63
63
|
)
|
|
64
64
|
|
|
65
65
|
async def add_client(self, websocket: WebSocket) -> None:
|
flock/engines/dspy_engine.py
CHANGED
|
@@ -242,19 +242,51 @@ class DSPyEngine(EngineComponent):
|
|
|
242
242
|
|
|
243
243
|
try:
|
|
244
244
|
if should_stream:
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
signature,
|
|
252
|
-
description=sys_desc,
|
|
253
|
-
payload=execution_payload,
|
|
254
|
-
agent=agent,
|
|
255
|
-
ctx=ctx,
|
|
256
|
-
pre_generated_artifact_id=pre_generated_artifact_id,
|
|
245
|
+
# Choose streaming method based on dashboard mode
|
|
246
|
+
is_dashboard = orchestrator and getattr(orchestrator, "is_dashboard", False)
|
|
247
|
+
|
|
248
|
+
# DEBUG: Log routing decision
|
|
249
|
+
logger.info(
|
|
250
|
+
f"[STREAMING ROUTER] agent={agent.name}, is_dashboard={is_dashboard}, orchestrator={orchestrator is not None}"
|
|
257
251
|
)
|
|
252
|
+
|
|
253
|
+
if is_dashboard:
|
|
254
|
+
# Dashboard mode: WebSocket-only streaming (no Rich overhead)
|
|
255
|
+
# This eliminates the Rich Live context that causes deadlocks with MCP tools
|
|
256
|
+
logger.info(
|
|
257
|
+
f"[STREAMING ROUTER] Routing {agent.name} to WebSocket-only method (dashboard mode)"
|
|
258
|
+
)
|
|
259
|
+
(
|
|
260
|
+
raw_result,
|
|
261
|
+
_stream_final_display_data,
|
|
262
|
+
) = await self._execute_streaming_websocket_only(
|
|
263
|
+
dspy_mod,
|
|
264
|
+
program,
|
|
265
|
+
signature,
|
|
266
|
+
description=sys_desc,
|
|
267
|
+
payload=execution_payload,
|
|
268
|
+
agent=agent,
|
|
269
|
+
ctx=ctx,
|
|
270
|
+
pre_generated_artifact_id=pre_generated_artifact_id,
|
|
271
|
+
)
|
|
272
|
+
else:
|
|
273
|
+
# CLI mode: Rich streaming with terminal display
|
|
274
|
+
logger.info(
|
|
275
|
+
f"[STREAMING ROUTER] Routing {agent.name} to Rich streaming method (CLI mode)"
|
|
276
|
+
)
|
|
277
|
+
(
|
|
278
|
+
raw_result,
|
|
279
|
+
_stream_final_display_data,
|
|
280
|
+
) = await self._execute_streaming(
|
|
281
|
+
dspy_mod,
|
|
282
|
+
program,
|
|
283
|
+
signature,
|
|
284
|
+
description=sys_desc,
|
|
285
|
+
payload=execution_payload,
|
|
286
|
+
agent=agent,
|
|
287
|
+
ctx=ctx,
|
|
288
|
+
pre_generated_artifact_id=pre_generated_artifact_id,
|
|
289
|
+
)
|
|
258
290
|
if not self.no_output and ctx:
|
|
259
291
|
ctx.state["_flock_stream_live_active"] = True
|
|
260
292
|
else:
|
|
@@ -503,6 +535,221 @@ class DSPyEngine(EngineComponent):
|
|
|
503
535
|
# Handle old format: direct payload (backwards compatible)
|
|
504
536
|
return program(description=description, input=payload, context=[])
|
|
505
537
|
|
|
538
|
+
async def _execute_streaming_websocket_only(
|
|
539
|
+
self,
|
|
540
|
+
dspy_mod,
|
|
541
|
+
program,
|
|
542
|
+
signature,
|
|
543
|
+
*,
|
|
544
|
+
description: str,
|
|
545
|
+
payload: dict[str, Any],
|
|
546
|
+
agent: Any,
|
|
547
|
+
ctx: Any = None,
|
|
548
|
+
pre_generated_artifact_id: Any = None,
|
|
549
|
+
) -> tuple[Any, None]:
|
|
550
|
+
"""Execute streaming for WebSocket only (no Rich display).
|
|
551
|
+
|
|
552
|
+
Optimized path for dashboard mode that skips all Rich formatting overhead.
|
|
553
|
+
Used when multiple agents stream in parallel to avoid terminal conflicts
|
|
554
|
+
and deadlocks with MCP tools.
|
|
555
|
+
|
|
556
|
+
This method eliminates the Rich Live context that can cause deadlocks when
|
|
557
|
+
combined with MCP tool execution and parallel agent streaming.
|
|
558
|
+
"""
|
|
559
|
+
logger.info(f"Agent {agent.name}: Starting WebSocket-only streaming (dashboard mode)")
|
|
560
|
+
|
|
561
|
+
# Get WebSocketManager
|
|
562
|
+
ws_manager = None
|
|
563
|
+
if ctx:
|
|
564
|
+
orchestrator = getattr(ctx, "orchestrator", None)
|
|
565
|
+
if orchestrator:
|
|
566
|
+
collector = getattr(orchestrator, "_dashboard_collector", None)
|
|
567
|
+
if collector:
|
|
568
|
+
ws_manager = getattr(collector, "_websocket_manager", None)
|
|
569
|
+
|
|
570
|
+
if not ws_manager:
|
|
571
|
+
logger.warning(
|
|
572
|
+
f"Agent {agent.name}: No WebSocket manager, falling back to standard execution"
|
|
573
|
+
)
|
|
574
|
+
result = await self._execute_standard(
|
|
575
|
+
dspy_mod, program, description=description, payload=payload
|
|
576
|
+
)
|
|
577
|
+
return result, None
|
|
578
|
+
|
|
579
|
+
# Get artifact type name for WebSocket events
|
|
580
|
+
artifact_type_name = "output"
|
|
581
|
+
if hasattr(agent, "outputs") and agent.outputs:
|
|
582
|
+
artifact_type_name = agent.outputs[0].spec.type_name
|
|
583
|
+
|
|
584
|
+
# Prepare stream listeners
|
|
585
|
+
listeners = []
|
|
586
|
+
try:
|
|
587
|
+
streaming_mod = getattr(dspy_mod, "streaming", None)
|
|
588
|
+
if streaming_mod and hasattr(streaming_mod, "StreamListener"):
|
|
589
|
+
for name, field in signature.output_fields.items():
|
|
590
|
+
if field.annotation is str:
|
|
591
|
+
listeners.append(streaming_mod.StreamListener(signature_field_name=name))
|
|
592
|
+
except Exception:
|
|
593
|
+
listeners = []
|
|
594
|
+
|
|
595
|
+
# Create streaming task
|
|
596
|
+
streaming_task = dspy_mod.streamify(
|
|
597
|
+
program,
|
|
598
|
+
is_async_program=True,
|
|
599
|
+
stream_listeners=listeners if listeners else None,
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
# Execute with appropriate payload format
|
|
603
|
+
if isinstance(payload, dict) and "input" in payload:
|
|
604
|
+
stream_generator = streaming_task(
|
|
605
|
+
description=description,
|
|
606
|
+
input=payload["input"],
|
|
607
|
+
context=payload.get("context", []),
|
|
608
|
+
)
|
|
609
|
+
else:
|
|
610
|
+
stream_generator = streaming_task(description=description, input=payload, context=[])
|
|
611
|
+
|
|
612
|
+
# Process stream (WebSocket only, no Rich display)
|
|
613
|
+
final_result = None
|
|
614
|
+
stream_sequence = 0
|
|
615
|
+
|
|
616
|
+
# Track background WebSocket broadcast tasks to prevent garbage collection
|
|
617
|
+
# Using fire-and-forget pattern to avoid blocking DSPy's streaming loop
|
|
618
|
+
ws_broadcast_tasks: set[asyncio.Task] = set()
|
|
619
|
+
|
|
620
|
+
async for value in stream_generator:
|
|
621
|
+
try:
|
|
622
|
+
from dspy.streaming import StatusMessage, StreamResponse
|
|
623
|
+
from litellm import ModelResponseStream
|
|
624
|
+
except Exception:
|
|
625
|
+
StatusMessage = object # type: ignore
|
|
626
|
+
StreamResponse = object # type: ignore
|
|
627
|
+
ModelResponseStream = object # type: ignore
|
|
628
|
+
|
|
629
|
+
if isinstance(value, StatusMessage):
|
|
630
|
+
token = getattr(value, "message", "")
|
|
631
|
+
if token:
|
|
632
|
+
try:
|
|
633
|
+
event = StreamingOutputEvent(
|
|
634
|
+
correlation_id=str(ctx.correlation_id)
|
|
635
|
+
if ctx and ctx.correlation_id
|
|
636
|
+
else "",
|
|
637
|
+
agent_name=agent.name,
|
|
638
|
+
run_id=ctx.task_id if ctx else "",
|
|
639
|
+
output_type="log",
|
|
640
|
+
content=str(token + "\n"),
|
|
641
|
+
sequence=stream_sequence,
|
|
642
|
+
is_final=False,
|
|
643
|
+
artifact_id=str(pre_generated_artifact_id),
|
|
644
|
+
artifact_type=artifact_type_name,
|
|
645
|
+
)
|
|
646
|
+
# Fire-and-forget to avoid blocking DSPy's streaming loop
|
|
647
|
+
task = asyncio.create_task(ws_manager.broadcast(event))
|
|
648
|
+
ws_broadcast_tasks.add(task)
|
|
649
|
+
task.add_done_callback(ws_broadcast_tasks.discard)
|
|
650
|
+
stream_sequence += 1
|
|
651
|
+
except Exception as e:
|
|
652
|
+
logger.warning(f"Failed to emit streaming event: {e}")
|
|
653
|
+
|
|
654
|
+
elif isinstance(value, StreamResponse):
|
|
655
|
+
token = getattr(value, "chunk", None)
|
|
656
|
+
if token:
|
|
657
|
+
try:
|
|
658
|
+
event = StreamingOutputEvent(
|
|
659
|
+
correlation_id=str(ctx.correlation_id)
|
|
660
|
+
if ctx and ctx.correlation_id
|
|
661
|
+
else "",
|
|
662
|
+
agent_name=agent.name,
|
|
663
|
+
run_id=ctx.task_id if ctx else "",
|
|
664
|
+
output_type="llm_token",
|
|
665
|
+
content=str(token),
|
|
666
|
+
sequence=stream_sequence,
|
|
667
|
+
is_final=False,
|
|
668
|
+
artifact_id=str(pre_generated_artifact_id),
|
|
669
|
+
artifact_type=artifact_type_name,
|
|
670
|
+
)
|
|
671
|
+
# Fire-and-forget to avoid blocking DSPy's streaming loop
|
|
672
|
+
task = asyncio.create_task(ws_manager.broadcast(event))
|
|
673
|
+
ws_broadcast_tasks.add(task)
|
|
674
|
+
task.add_done_callback(ws_broadcast_tasks.discard)
|
|
675
|
+
stream_sequence += 1
|
|
676
|
+
except Exception as e:
|
|
677
|
+
logger.warning(f"Failed to emit streaming event: {e}")
|
|
678
|
+
|
|
679
|
+
elif isinstance(value, ModelResponseStream):
|
|
680
|
+
chunk = value
|
|
681
|
+
token = chunk.choices[0].delta.content or ""
|
|
682
|
+
if token:
|
|
683
|
+
try:
|
|
684
|
+
event = StreamingOutputEvent(
|
|
685
|
+
correlation_id=str(ctx.correlation_id)
|
|
686
|
+
if ctx and ctx.correlation_id
|
|
687
|
+
else "",
|
|
688
|
+
agent_name=agent.name,
|
|
689
|
+
run_id=ctx.task_id if ctx else "",
|
|
690
|
+
output_type="llm_token",
|
|
691
|
+
content=str(token),
|
|
692
|
+
sequence=stream_sequence,
|
|
693
|
+
is_final=False,
|
|
694
|
+
artifact_id=str(pre_generated_artifact_id),
|
|
695
|
+
artifact_type=artifact_type_name,
|
|
696
|
+
)
|
|
697
|
+
# Fire-and-forget to avoid blocking DSPy's streaming loop
|
|
698
|
+
task = asyncio.create_task(ws_manager.broadcast(event))
|
|
699
|
+
ws_broadcast_tasks.add(task)
|
|
700
|
+
task.add_done_callback(ws_broadcast_tasks.discard)
|
|
701
|
+
stream_sequence += 1
|
|
702
|
+
except Exception as e:
|
|
703
|
+
logger.warning(f"Failed to emit streaming event: {e}")
|
|
704
|
+
|
|
705
|
+
elif isinstance(value, dspy_mod.Prediction):
|
|
706
|
+
final_result = value
|
|
707
|
+
# Send final events
|
|
708
|
+
try:
|
|
709
|
+
event = StreamingOutputEvent(
|
|
710
|
+
correlation_id=str(ctx.correlation_id)
|
|
711
|
+
if ctx and ctx.correlation_id
|
|
712
|
+
else "",
|
|
713
|
+
agent_name=agent.name,
|
|
714
|
+
run_id=ctx.task_id if ctx else "",
|
|
715
|
+
output_type="log",
|
|
716
|
+
content=f"\nAmount of output tokens: {stream_sequence}",
|
|
717
|
+
sequence=stream_sequence,
|
|
718
|
+
is_final=True,
|
|
719
|
+
artifact_id=str(pre_generated_artifact_id),
|
|
720
|
+
artifact_type=artifact_type_name,
|
|
721
|
+
)
|
|
722
|
+
# Fire-and-forget to avoid blocking DSPy's streaming loop
|
|
723
|
+
task = asyncio.create_task(ws_manager.broadcast(event))
|
|
724
|
+
ws_broadcast_tasks.add(task)
|
|
725
|
+
task.add_done_callback(ws_broadcast_tasks.discard)
|
|
726
|
+
|
|
727
|
+
event = StreamingOutputEvent(
|
|
728
|
+
correlation_id=str(ctx.correlation_id)
|
|
729
|
+
if ctx and ctx.correlation_id
|
|
730
|
+
else "",
|
|
731
|
+
agent_name=agent.name,
|
|
732
|
+
run_id=ctx.task_id if ctx else "",
|
|
733
|
+
output_type="log",
|
|
734
|
+
content="--- End of output ---",
|
|
735
|
+
sequence=stream_sequence + 1,
|
|
736
|
+
is_final=True,
|
|
737
|
+
artifact_id=str(pre_generated_artifact_id),
|
|
738
|
+
artifact_type=artifact_type_name,
|
|
739
|
+
)
|
|
740
|
+
# Fire-and-forget to avoid blocking DSPy's streaming loop
|
|
741
|
+
task = asyncio.create_task(ws_manager.broadcast(event))
|
|
742
|
+
ws_broadcast_tasks.add(task)
|
|
743
|
+
task.add_done_callback(ws_broadcast_tasks.discard)
|
|
744
|
+
except Exception as e:
|
|
745
|
+
logger.warning(f"Failed to emit final streaming event: {e}")
|
|
746
|
+
|
|
747
|
+
if final_result is None:
|
|
748
|
+
raise RuntimeError(f"Agent {agent.name}: Streaming did not yield a final prediction")
|
|
749
|
+
|
|
750
|
+
logger.info(f"Agent {agent.name}: WebSocket streaming completed ({stream_sequence} tokens)")
|
|
751
|
+
return final_result, None
|
|
752
|
+
|
|
506
753
|
async def _execute_streaming(
|
|
507
754
|
self,
|
|
508
755
|
dspy_mod,
|
|
@@ -571,12 +818,12 @@ class DSPyEngine(EngineComponent):
|
|
|
571
818
|
# Use the pre-generated artifact ID that was created before execution started
|
|
572
819
|
display_data["id"] = str(pre_generated_artifact_id)
|
|
573
820
|
|
|
574
|
-
# Get the
|
|
575
|
-
|
|
821
|
+
# Get the artifact type name from agent configuration
|
|
822
|
+
artifact_type_name = "output"
|
|
576
823
|
if hasattr(agent, "outputs") and agent.outputs:
|
|
577
|
-
|
|
824
|
+
artifact_type_name = agent.outputs[0].spec.type_name
|
|
578
825
|
|
|
579
|
-
display_data["type"] =
|
|
826
|
+
display_data["type"] = artifact_type_name
|
|
580
827
|
display_data["payload"] = OrderedDict()
|
|
581
828
|
|
|
582
829
|
# Add output fields to payload section
|
|
@@ -660,6 +907,10 @@ class DSPyEngine(EngineComponent):
|
|
|
660
907
|
content=str(token + "\n"),
|
|
661
908
|
sequence=stream_sequence,
|
|
662
909
|
is_final=False,
|
|
910
|
+
artifact_id=str(
|
|
911
|
+
pre_generated_artifact_id
|
|
912
|
+
), # Phase 6: Track artifact for message streaming
|
|
913
|
+
artifact_type=artifact_type_name, # Phase 6: Artifact type name
|
|
663
914
|
)
|
|
664
915
|
# Use create_task to avoid blocking the streaming loop
|
|
665
916
|
task = asyncio.create_task(ws_manager.broadcast(event))
|
|
@@ -704,6 +955,10 @@ class DSPyEngine(EngineComponent):
|
|
|
704
955
|
content=str(token),
|
|
705
956
|
sequence=stream_sequence,
|
|
706
957
|
is_final=False,
|
|
958
|
+
artifact_id=str(
|
|
959
|
+
pre_generated_artifact_id
|
|
960
|
+
), # Phase 6: Track artifact for message streaming
|
|
961
|
+
artifact_type=artifact_type_name, # Phase 6: Artifact type name
|
|
707
962
|
)
|
|
708
963
|
# Use create_task to avoid blocking the streaming loop
|
|
709
964
|
task = asyncio.create_task(ws_manager.broadcast(event))
|
|
@@ -722,9 +977,6 @@ class DSPyEngine(EngineComponent):
|
|
|
722
977
|
token = chunk.choices[0].delta.content or ""
|
|
723
978
|
signature_field = getattr(value, "signature_field_name", None)
|
|
724
979
|
|
|
725
|
-
# Determine output type based on signature field
|
|
726
|
-
output_type = "llm_token" # if signature_field and signature_field != "description" else "log"
|
|
727
|
-
|
|
728
980
|
if signature_field and signature_field != "description":
|
|
729
981
|
# Update payload section - accumulate in buffer
|
|
730
982
|
buffer_key = f"_stream_{signature_field}"
|
|
@@ -747,10 +999,16 @@ class DSPyEngine(EngineComponent):
|
|
|
747
999
|
else "",
|
|
748
1000
|
agent_name=agent.name,
|
|
749
1001
|
run_id=ctx.task_id if ctx else "",
|
|
750
|
-
output_type=
|
|
1002
|
+
output_type="llm_token",
|
|
751
1003
|
content=str(token),
|
|
752
1004
|
sequence=stream_sequence,
|
|
753
1005
|
is_final=False,
|
|
1006
|
+
artifact_id=str(
|
|
1007
|
+
pre_generated_artifact_id
|
|
1008
|
+
), # Phase 6: Track artifact for message streaming
|
|
1009
|
+
artifact_type=display_data[
|
|
1010
|
+
"type"
|
|
1011
|
+
], # Phase 6: Artifact type name from display_data
|
|
754
1012
|
)
|
|
755
1013
|
# Use create_task to avoid blocking the streaming loop
|
|
756
1014
|
task = asyncio.create_task(ws_manager.broadcast(event))
|
|
@@ -780,6 +1038,10 @@ class DSPyEngine(EngineComponent):
|
|
|
780
1038
|
content="\nAmount of output tokens: " + str(stream_sequence),
|
|
781
1039
|
sequence=stream_sequence,
|
|
782
1040
|
is_final=True, # Mark as final
|
|
1041
|
+
artifact_id=str(
|
|
1042
|
+
pre_generated_artifact_id
|
|
1043
|
+
), # Phase 6: Track artifact for message streaming
|
|
1044
|
+
artifact_type=display_data["type"], # Phase 6: Artifact type name
|
|
783
1045
|
)
|
|
784
1046
|
# Use create_task to avoid blocking the streaming loop
|
|
785
1047
|
task = asyncio.create_task(ws_manager.broadcast(event))
|
|
@@ -795,6 +1057,10 @@ class DSPyEngine(EngineComponent):
|
|
|
795
1057
|
content="--- End of output ---",
|
|
796
1058
|
sequence=stream_sequence,
|
|
797
1059
|
is_final=True, # Mark as final
|
|
1060
|
+
artifact_id=str(
|
|
1061
|
+
pre_generated_artifact_id
|
|
1062
|
+
), # Phase 6: Track artifact for message streaming
|
|
1063
|
+
artifact_type=display_data["type"], # Phase 6: Artifact type name
|
|
798
1064
|
)
|
|
799
1065
|
# Use create_task to avoid blocking the streaming loop
|
|
800
1066
|
task = asyncio.create_task(ws_manager.broadcast(event))
|
|
@@ -911,3 +1177,11 @@ __all__ = ["DSPyEngine"]
|
|
|
911
1177
|
|
|
912
1178
|
# Apply the Rich Live patch when this module is imported
|
|
913
1179
|
_apply_live_patch_on_import()
|
|
1180
|
+
|
|
1181
|
+
# Apply the DSPy streaming patch to fix deadlocks with MCP tools
|
|
1182
|
+
try:
|
|
1183
|
+
from flock.patches.dspy_streaming_patch import apply_patch as apply_dspy_streaming_patch
|
|
1184
|
+
|
|
1185
|
+
apply_dspy_streaming_patch()
|
|
1186
|
+
except Exception:
|
|
1187
|
+
pass # Silently ignore if patch fails to apply
|
flock/frontend/README.md
CHANGED
|
@@ -149,7 +149,7 @@ Launch the module via the context menu (or `Add Module → Historical Blackboard
|
|
|
149
149
|
|
|
150
150
|
- **Node.js**: Version 18 or higher
|
|
151
151
|
- **Package Manager**: npm (included with Node.js) or yarn
|
|
152
|
-
- **Flock Flow Backend**: Running orchestrator instance (typically on port
|
|
152
|
+
- **Flock Flow Backend**: Running orchestrator instance (typically on port 8344)
|
|
153
153
|
|
|
154
154
|
### Installation
|
|
155
155
|
|
|
@@ -205,11 +205,11 @@ The dashboard can be configured via environment variables:
|
|
|
205
205
|
|
|
206
206
|
```bash
|
|
207
207
|
# .env file
|
|
208
|
-
VITE_WS_URL=ws://localhost:
|
|
209
|
-
VITE_API_URL=http://localhost:
|
|
208
|
+
VITE_WS_URL=ws://localhost:8344/ws
|
|
209
|
+
VITE_API_URL=http://localhost:8344/api
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
If not specified, defaults to `localhost:
|
|
212
|
+
If not specified, defaults to `localhost:8344`.
|
|
213
213
|
|
|
214
214
|
## Design System
|
|
215
215
|
|
|
@@ -596,7 +596,7 @@ npm run type-check
|
|
|
596
596
|
|
|
597
597
|
**Solutions**:
|
|
598
598
|
1. Check browser console for errors (F12)
|
|
599
|
-
2. Verify backend is running on port
|
|
599
|
+
2. Verify backend is running on port 8344
|
|
600
600
|
3. Check WebSocket connection status in UI
|
|
601
601
|
4. Clear IndexedDB: Open DevTools → Application → IndexedDB → Delete
|
|
602
602
|
5. Clear localStorage: `localStorage.clear()` in console
|
|
@@ -606,7 +606,7 @@ npm run type-check
|
|
|
606
606
|
**Symptom**: "Disconnected" status indicator
|
|
607
607
|
|
|
608
608
|
**Solutions**:
|
|
609
|
-
1. Verify backend WebSocket endpoint is accessible: `ws://localhost:
|
|
609
|
+
1. Verify backend WebSocket endpoint is accessible: `ws://localhost:8344/ws`
|
|
610
610
|
2. Check for CORS issues in browser console
|
|
611
611
|
3. Check network tab for WebSocket connection attempts
|
|
612
612
|
4. Restart the backend server
|