Skip to content

Commit 126c037

Browse files
Wallgauautofix-ci[bot]lucaseduolikeval718Olfa Maslah
authored
feat: fork branch for main (#11183)
* feat: add chat-header feature and sliding container (#11045) Add sliding playground layout (SimpleSidebar + sliding container + store) and toolbar button integration to open it directly + chat header/session components and hooks (SessionSelector, SessionRename, ChatHeaderTitle, use-get-flow-id, playgroundStore). * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes * removed changes on the tailwind config * feat: add session management functionality (#11272) * feat: add session management functionality - Add session selector component - Add session more menu component - Add session header component - Add session edit info hook - Add get/add sessions hook - Hide delete button for default session * sync: update animated-close and simple-sidebar from pr4 * Make sidebar continue to be fullscreen after closing and opening * [autofix.ci] apply automated fixes * reduce max width * Pr2 bis chat messages (#11308) * feat: add chat messages components and infrastructure - Add bot message component - Add thinking message component - Add user message component - Add chat message wrapper component - Add message editing functionality - Add error message component - Add file card wrapper - Add message options component - Add chat history hook - Add thinking duration hook - Add typing effect hook - Add message utilities (convert files, format file name, sort messages) - Add content block display component - Add send message hook * fix: remove typing animation from bot messages, show thinking immediately after user message, and use optional chaining for updateChat * [autofix.ci] apply automated fixes * feat: add streaming message hook and fix thinking/thought display logic - Extract streaming logic to useStreamingMessage hook matching IOModal behavior - Fix thinking/thought message display to use isBuilding directly from store - Remove typing animation logic from bot messages - Fix textarea resize to prevent growing on every keystroke with 10px threshold - Fix ContentBlockDisplay truncate styling for tool titles - Remove markdown bold syntax (**) from tool titles - Fix ContentDisplay type error * refactor: sync chat-messages from pr3 with refactored utilities - Copy refactored chat-messages components from pr3 - Add new hooks: use-message-duration, use-tool-durations - Add consolidated utilities: format.ts, content-blocks.ts, extract-error-message.ts - Add Indicator icon for error messages - Update ContentBlockDisplay to use new utilities - Remove format-file-name.tsx (merged into format.ts) - Update lazyIconImports to include Indicator icon * sync: update animated-close and simple-sidebar from pr4 * Pr3 chat input (#11310) * feat: add chat input components and improvements - Add chat input component - Add text area wrapper with auto-resize - Add input wrapper component - Add button send wrapper - Add no-input component - Add audio button component - Add file preview component - Add upload file button - Add auto-resize text area hook - Add audio recording hook - Add drag and drop hook - Update textarea UI component - Update IOModal input wrapper - Update constants for chat input * feat: add file handling, UI enhancements, types, stores and dependencies - Add file preview display component - Add file utilities - Add animated close component - Add simple sidebar component - Update sliding container with container queries support - Update FlowPage components - Update styles and Tailwind config - Add chat types - Add component types - Add utility store types - Add utility store - Update package dependencies * fix: prevent chat input from growing on every letter and make updateChat optional with proper typing * fix: prevent chat input from growing on every letter * fix: sync message components with PR2 (remove typing animation, fix thinking timing, use optional chaining) * fix: sync message components with PR2 (remove typing animation, fix thinking timing, use optional chaining) * [autofix.ci] apply automated fixes * fix: apply message component fixes from PR2 (remove typing animation, fix thinking timing, use optional chaining) * [autofix.ci] apply automated fixes * fix: prevent textarea from resizing on every character by tracking previous scrollHeight * fix: prevent textarea from resizing on every character by tracking previous scrollHeight * fix: prevent textarea from growing on every character with 10px threshold * fix: prevent textarea from growing on every character with 10px threshold * Revert "fix: prevent textarea from growing on every character with 10px threshold" This reverts commit ec3ed63. * Revert "fix: prevent textarea from growing on every character with 10px threshold" This reverts commit 93637ae. * feat: add streaming message hook and fix thinking/thought display logic - Extract streaming logic to useStreamingMessage hook matching IOModal behavior - Fix thinking/thought message display to use isBuilding directly from store - Remove typing animation logic from bot messages - Fix textarea resize to prevent growing on every keystroke with 10px threshold - Fix ContentBlockDisplay truncate styling for tool titles - Remove markdown bold syntax (**) from tool titles - Fix ContentDisplay type error * feat: add streaming message hook and fix thinking/thought display logic - Extract streaming logic to useStreamingMessage hook matching IOModal behavior - Fix thinking/thought message display to use isBuilding directly from store - Remove typing animation logic from bot messages - Fix textarea resize to prevent growing on every keystroke with 10px threshold - Fix ContentBlockDisplay truncate styling for tool titles - Remove markdown bold syntax (**) from tool titles - Fix ContentDisplay type error * fix error making the flow crashing * resize user and bot icon and remove borders * fix flow crash when error * have the green duration be the sum of tool and sec part the entire thinking * refactor: extract and consolidate chat message utilities - Extract duration tracking logic to use-message-duration hook - Consolidate format utilities (formatTime, formatSeconds, formatToolTitle, formatFileName) into single format.ts file - Merge content block utilities (getContentBlockState, getContentBlockLoadingState) into content-blocks.ts - Move component-specific logic (hasTools, shouldShowAvatar, shouldShowContentBlocks) back into components - Move errorMarkdownComponents into error-message.tsx component - Simplify error-message.tsx by extracting sub-components - Add Indicator icon for error messages - Update all imports to use consolidated utilities * refactor: sync chat-messages and chat-input from pr4 - Copy refactored chat-messages components from pr4 - Add new hooks: use-message-duration, use-tool-durations - Add consolidated utilities: format.ts, content-blocks.ts, extract-error-message.ts - Add Indicator icon for error messages - Update ContentBlockDisplay to use new utilities - Remove format-file-name.tsx (merged into format.ts) - Update lazyIconImports to include Indicator icon * change duration animation * Only allow certain file types * feat: add file handling, UI enhancements, types, stores and dependencies (#11276) * [autofix.ci] apply automated fixes * feat: add clear chat option for default session in session management - Add 'Clear chat' option to SessionMoreMenu component - Show 'Clear chat' for default session (currentSessionId === currentFlowId) - Show 'Delete' for other sessions (existing behavior) - Clear chat deletes messages but keeps the session - Delete removes the entire session - Both options use same red color styling * adjust radius for error message border * show only the text An error occured * refactor: replace Zustand with React Query for message handling - Move all message handling logic to chat-view/utils/ - Create message-event-handler.ts to handle build events - Create message-utils.ts for React Query cache operations - Update buildUtils.ts to delegate message events to chat-view - Remove MemoizedChatMessage to fix streaming updates - Simplify use-chat-history to use session cache as single source of truth - Support placeholder messages for immediate UI feedback - Handle streaming tokens with proper text accumulation * fix: improve clear chat logic to prevent double clearing - Fix clearSessionMessages to use removeQueries instead of invalidateQueries - Prevents refetch that brings back deleted messages - Clear chat only works for default session, delete works for other sessions - Handle default session messages with null session_id (legacy) * fix padding and spacing issue on playground component * fix: message section padding * fix: padding * add time persistence and build perfect timer * [autofix.ci] apply automated fixes * fix display time styles * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes * fix: format time in seconds and fix gap between duration and message * [autofix.ci] apply automated fixes * fix: fetch messages in session logs modal to prevent empty display * [autofix.ci] apply automated fixes * fix: added gap between image and message * fix header truncating * fix: apply card in the background of user message in smaller view --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Olfa Maslah <olfamaslah@Olfas-MacBook-Pro.local> Co-authored-by: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com> Co-authored-by: Keval718 <kevalvirat@gmail.com> Co-authored-by: cristhianzl <cristhian.lousa@gmail.com> Co-authored-by: Lucas Oliveira <lucas.edu.oli@hotmail.com> --------- Co-authored-by: Olfa Maslah <olfamaslah@Olfas-MacBook-Pro.local> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com> Co-authored-by: Lucas Oliveira <lucas.edu.oli@hotmail.com> Co-authored-by: Keval718 <kevalvirat@gmail.com> Co-authored-by: cristhianzl <cristhian.lousa@gmail.com> --------- Co-authored-by: Olfa Maslah <olfamaslah@Olfas-MacBook-Pro.local> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com> Co-authored-by: Lucas Oliveira <lucas.edu.oli@hotmail.com> Co-authored-by: Keval718 <kevalvirat@gmail.com> Co-authored-by: cristhianzl <cristhian.lousa@gmail.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) --------- Co-authored-by: Olfa Maslah <olfamaslah@Olfas-MacBook-Pro.local> Co-authored-by: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com> Co-authored-by: Lucas Oliveira <lucas.edu.oli@hotmail.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Keval718 <kevalvirat@gmail.com> Co-authored-by: cristhianzl <cristhian.lousa@gmail.com> * fix: frontend tests * [autofix.ci] apply automated fixes * fix nested agents * [autofix.ci] apply automated fixes * Revert "fix nested agents" This reverts commit f230c8c. * fix time on agent chain * [autofix.ci] apply automated fixes * fix(playground): display ChatInput default value on playground open (#11514) * fix(playground): display ChatInput default value on playground open * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix(ui): prevent layout shift when adding Chat Input with closed playground (#11531) * fix(ui): prevent layout shift when adding Chat Input with closed playground * fix(ui): remove unwanted import * fix(frontend): reset playground state when navigating between flows (#11533) reset playground state when leaving the flow * fix(frontend): prevent Message Logs table from dropping columns with falsy values (#11540) fix(frontend): prevent Message Logs table from dropping columns with falsy values * fix(frontend): auto-close playground when all chat components are removed (#11537) * fix(frontend): auto-close playground when all chat components are removed * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix(frontend): prevent send button from being pushed off-screen in chat input (#11556) * fix(frontend): prevent send button from being pushed off-screen in chat input * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix(test): fix image upload process in chat input test * fix(test): improve chat message verification in chat input test * fix: add data-testID to ensure the testcases pass (#11573) Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.war.can.ibm.com> * feat(tests): add data-testid attributes for improved test targeting in chat header and session selector * fix: session rename create new session instead of remaining existing one (#11576) * fix(frontend): resolve session rename bugs and prevent message loss * fix(playground): Fix session rename not showing messages immediately * [autofix.ci] apply automated fixes * fix(playground): Eliminate duplicate logic in session-selector --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix(test): playground test * fix: rename session and test shard 9 (#11581) fix: pass renameLocalSession to ChatHeader to fix session rename creating new session The session rename from the chat header's more menu was creating a new session instead of renaming the existing one. This was because renameLocalSession was not being passed to useEditSessionInfo in chat-header.tsx. - Added renameLocalSession to ChatHeaderProps type - Pass renameLocalSession from flow-page-sliding-container to ChatHeader - Pass renameLocalSession to useEditSessionInfo in chat-header * fix(frontend): prevent menu stacking and ensure proper close behavior (#11592) * fix(frontend): prevent menu stacking and ensure proper close behavior * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: playground tests shard 13 (#11593) * fix: update Basic Prompting test to use specific test IDs for playground combobox * fix: skip voice assistant interaction test for review * test: skip voice-assistant tests pending playground refactor * fix: tests shard 16 (#11594) * fix: update Basic Prompting test to use specific test IDs for playground combobox * fix: skip voice assistant interaction test for review * test: skip voice-assistant tests pending playground refactor * fix: update Financial Report Parser and Image Sentiment Analysis tests - Financial Report Parser: Use stop_building_button instead of button-stop (which doesn't exist in playground chat input), wait for it to appear before waiting for hidden state, and use div-chat-message instead of .markdown selector which was matching node descriptions - Image Sentiment Analysis: Replace unreliable dispatchEvent("drop") with setInputFiles() for file upload, add proper flow completion wait, and use img[alt$="chain.png"] to handle server timestamp prefix * fix(frontend): prevent duplicate session creation when renaming in non fullscreen mode (#11596) fix(frontend): prevent duplicate session creation when renaming in non-fullscreen mode * fix: tests shard 18 - Memory Chatbot and Simple Agent Memory (#11597) Memory Chatbot: - Replace fragile selectors (getByRole, getByLabel) with data-testid - Use chat-header-more-menu and message-logs-option for message logs - Replace .isVisible() with proper expect().toBeVisible() assertions - Simplify test by removing session deletion Simple Agent Memory: - Add waitForSelector for input before filling - Use stop_building_button instead of getByRole("button", { name: "Stop" }) - Use proper wait pattern: visible → hidden for build completion - Add user message verification with chat-message-User-* test IDs - Add wait for div-chat-message before asserting * fix: update News Aggregator test to streamline API key handling and increase timeout (#11598) * fix: tests shard 18 - Memory Chatbot and Simple Agent Memory Memory Chatbot: - Replace fragile selectors (getByRole, getByLabel) with data-testid - Use chat-header-more-menu and message-logs-option for message logs - Replace .isVisible() with proper expect().toBeVisible() assertions - Simplify test by removing session deletion Simple Agent Memory: - Add waitForSelector for input before filling - Use stop_building_button instead of getByRole("button", { name: "Stop" }) - Use proper wait pattern: visible → hidden for build completion - Add user message verification with chat-message-User-* test IDs - Add wait for div-chat-message before asserting * fix: update News Aggregator test to streamline API key handling and increase timeout * fix: refactor Pokedex Agent test for improved readability and consistency * fix: update Pokedex Agent test to correctly retrieve chat message output and adjust length expectation * fix: improve Research Translation Loop test structure and readability * fix: enhance readability and consistency in Simple Agent Memory test * fix: generalBugs-shard-9 test * fix: simplify file upload handling in limit-file-size-upload test * fix: file upload test * fix: update chat interaction test for improved sender name handling * fix: add data-testid attribute to hidden file input for improved test targeting * fix: refactor test structure for improved readability and maintainability * fix: revert upload file util --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Lucas Oliveira <lucas.edu.oli@hotmail.com> Co-authored-by: keval shah <kevalvirat@gmail.com> Co-authored-by: Olfa Maslah <olfamaslah@Olfas-MacBook-Pro.local> Co-authored-by: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com> Co-authored-by: cristhianzl <cristhian.lousa@gmail.com> Co-authored-by: Viktor Avelino <viktor.avelino@gmail.com> Co-authored-by: olayinkaadelakun <olayinka.adelakun@ibm.com> Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.war.can.ibm.com> Co-authored-by: Viktor Avelino <64113566+viktoravelino@users.noreply.github.com>
1 parent 41caeb9 commit 126c037

136 files changed

Lines changed: 8214 additions & 741 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.secrets.baseline

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,23 +1453,23 @@
14531453
"filename": "src/frontend/src/constants/constants.ts",
14541454
"hashed_secret": "19a2fbd0dd38b4097f419c962342ef5e109eab07",
14551455
"is_verified": false,
1456-
"line_number": 755,
1456+
"line_number": 763,
14571457
"is_secret": false
14581458
},
14591459
{
14601460
"type": "Secret Keyword",
14611461
"filename": "src/frontend/src/constants/constants.ts",
14621462
"hashed_secret": "3806954324550e26ef5de85d007f1746825a073c",
14631463
"is_verified": false,
1464-
"line_number": 756,
1464+
"line_number": 764,
14651465
"is_secret": false
14661466
},
14671467
{
14681468
"type": "Secret Keyword",
14691469
"filename": "src/frontend/src/constants/constants.ts",
14701470
"hashed_secret": "c04f8fbf55c9096907a982750b1c6b0e4c1dd658",
14711471
"is_verified": false,
1472-
"line_number": 930,
1472+
"line_number": 939,
14731473
"is_secret": false
14741474
}
14751475
],

src/backend/base/langflow/api/build.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -373,13 +373,6 @@ async def _build_vertex(vertex_id: str, graph: Graph, event_manager: EventManage
373373

374374
timedelta = time.perf_counter() - start_time
375375

376-
# Use client_request_time if available for accurate end-to-end duration
377-
if inputs and inputs.client_request_time:
378-
# Convert client timestamp (ms) to seconds and calculate elapsed time
379-
client_start_seconds = inputs.client_request_time / 1000
380-
current_time_seconds = time.time()
381-
timedelta = current_time_seconds - client_start_seconds
382-
383376
duration = format_elapsed_time(timedelta)
384377
result_data_response.duration = duration
385378
result_data_response.timedelta = timedelta
@@ -454,20 +447,26 @@ async def build_vertices(
454447
vertex_id: str,
455448
graph: Graph,
456449
event_manager: EventManager,
450+
vertex_timedeltas: list[float],
457451
) -> None:
458452
"""Build vertices and handle their events.
459453
460454
Args:
461455
vertex_id: The ID of the vertex to build
462456
graph: The graph instance
463457
event_manager: Manager for handling events
458+
vertex_timedeltas: Shared list to accumulate each vertex's timedelta
464459
"""
465460
try:
466461
vertex_build_response: VertexBuildResponse = await _build_vertex(vertex_id, graph, event_manager)
467462
except asyncio.CancelledError as exc:
468463
await logger.ainfo(f"Build cancelled: {exc}")
469464
raise
470465

466+
# Accumulate the vertex timedelta
467+
if vertex_build_response.data.timedelta is not None:
468+
vertex_timedeltas.append(vertex_build_response.data.timedelta)
469+
471470
# send built event or error event
472471
try:
473472
vertex_build_response_json = vertex_build_response.model_dump_json()
@@ -486,6 +485,7 @@ async def build_vertices(
486485
next_vertex_id,
487486
graph,
488487
event_manager,
488+
vertex_timedeltas,
489489
)
490490
)
491491
tasks.append(task)
@@ -503,9 +503,11 @@ async def build_vertices(
503503

504504
event_manager.on_vertices_sorted(data={"ids": ids, "to_run": vertices_to_run})
505505

506+
vertex_timedeltas: list[float] = []
507+
event_manager.on_build_start(data={})
506508
tasks = []
507509
for vertex_id in ids:
508-
task = asyncio.create_task(build_vertices(vertex_id, graph, event_manager))
510+
task = asyncio.create_task(build_vertices(vertex_id, graph, event_manager, vertex_timedeltas))
509511
tasks.append(task)
510512
try:
511513
await asyncio.gather(*tasks)
@@ -525,7 +527,8 @@ async def build_vertices(
525527
event_manager.on_error(data=error_message.data)
526528
raise
527529

528-
event_manager.on_end(data={})
530+
build_duration = sum(vertex_timedeltas)
531+
event_manager.on_end(data={"build_duration": build_duration})
529532
await graph.end_all_traces()
530533
await event_manager.queue.put((None, None, time.time()))
531534

src/backend/base/langflow/api/utils/core.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def format_elapsed_time(elapsed_time: float) -> str:
150150
"""Format elapsed time to a human-readable format coming from perf_counter().
151151
152152
- Less than 1 second: returns milliseconds
153-
- Less than 1 minute: returns seconds rounded to 2 decimals
153+
- Less than 1 minute: returns seconds rounded to 1 decimal
154154
- 1 minute or more: returns minutes and seconds
155155
"""
156156
delta = timedelta(seconds=elapsed_time)
@@ -159,12 +159,12 @@ def format_elapsed_time(elapsed_time: float) -> str:
159159
return f"{milliseconds} ms"
160160

161161
if delta < timedelta(minutes=1):
162-
seconds = round(elapsed_time, 2)
162+
seconds = round(elapsed_time, 1)
163163
unit = "second" if seconds == 1 else "seconds"
164164
return f"{seconds} {unit}"
165165

166166
minutes = delta // timedelta(minutes=1)
167-
seconds = round((delta - timedelta(minutes=minutes)).total_seconds(), 2)
167+
seconds = round((delta - timedelta(minutes=minutes)).total_seconds(), 1)
168168
minutes_unit = "minute" if minutes == 1 else "minutes"
169169
seconds_unit = "second" if seconds == 1 else "seconds"
170170
return f"{minutes} {minutes_unit}, {seconds} {seconds_unit}"

src/backend/base/langflow/api/v1/chat.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -368,13 +368,6 @@ async def build_vertex(
368368

369369
timedelta = time.perf_counter() - start_time
370370

371-
# Use client_request_time if available for accurate end-to-end duration
372-
if inputs and inputs.client_request_time:
373-
# Convert client timestamp (ms) to seconds and calculate elapsed time
374-
client_start_seconds = inputs.client_request_time / 1000
375-
current_time_seconds = time.time()
376-
timedelta = current_time_seconds - client_start_seconds
377-
378371
duration = format_elapsed_time(timedelta)
379372
result_data_response.duration = duration
380373
result_data_response.timedelta = timedelta

src/backend/base/langflow/schema/properties.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Properties(BaseModel):
2222
positive_feedback: bool | None = None
2323
state: Literal["partial", "complete"] = "complete"
2424
targets: list = []
25+
build_duration: float | None = None
2526

2627
@field_validator("source", mode="before")
2728
@classmethod

src/backend/tests/unit/components/inputs/test_input_components.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ async def test_message_response(self, component_class, default_kwargs):
5353
"allow_markdown": False,
5454
"state": "complete",
5555
"targets": [],
56+
"build_duration": None,
5657
}
5758

5859
async def test_message_response_ai_sender(self, component_class):

src/backend/tests/unit/test_build_timer.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,3 +321,68 @@ async def test_async_build_without_client_timestamp(self):
321321
# Should use perf_counter
322322
if not (inputs and inputs.client_request_time):
323323
assert 0.09 < duration < 0.15
324+
325+
326+
class TestVertexDurationUsesOwnPerfCounter:
327+
"""Vertex duration must always reflect its own execution time via perf_counter.
328+
329+
client_request_time must NOT override individual vertex timings because that
330+
would make sequential vertices (e.g. Agent → Chat Output) report the same
331+
cumulative wall-clock time instead of their own execution duration.
332+
"""
333+
334+
def test_should_use_perf_counter_when_client_request_time_is_set(self):
335+
"""Even when client_request_time exists, vertex duration must come from perf_counter."""
336+
# Arrange — client sent request 500ms ago
337+
client_start_ms = int((time.time() - 0.5) * 1000)
338+
inputs = InputValueRequest(input_value="test", client_request_time=client_start_ms)
339+
340+
# Act — simulate vertex build taking ~50ms
341+
start_time = time.perf_counter()
342+
time.sleep(0.05)
343+
timedelta = time.perf_counter() - start_time
344+
# No client_request_time override — this is the new behavior
345+
346+
# Assert — duration reflects only the vertex's own execution, not cumulative wall-clock
347+
assert inputs.client_request_time is not None, "Precondition: client_request_time is set"
348+
assert 0.04 < timedelta < 0.1, f"Expected ~50ms (own execution), got {timedelta}s"
349+
350+
def test_should_not_show_same_duration_for_sequential_vertices(self):
351+
"""Two sequential vertices must report different durations reflecting their own work."""
352+
# Act — first vertex (slow: ~100ms)
353+
start_1 = time.perf_counter()
354+
time.sleep(0.1)
355+
duration_1 = time.perf_counter() - start_1
356+
357+
# Act — second vertex (fast: ~20ms)
358+
start_2 = time.perf_counter()
359+
time.sleep(0.02)
360+
duration_2 = time.perf_counter() - start_2
361+
362+
# Assert — each vertex reports its own execution time
363+
assert 0.08 < duration_1 < 0.15, f"First vertex expected ~100ms, got {duration_1}s"
364+
assert 0.01 < duration_2 < 0.05, f"Second vertex expected ~20ms, got {duration_2}s"
365+
assert duration_1 > duration_2 * 2, "Slow vertex must be significantly longer than fast vertex"
366+
367+
def test_should_measure_only_vertex_execution_not_cumulative_time(self):
368+
"""Vertex duration must exclude time spent in prior vertices."""
369+
# Arrange — simulate a pipeline: Vertex A (100ms) → Vertex B (20ms)
370+
pipeline_start = time.time()
371+
372+
# Vertex A
373+
start_a = time.perf_counter()
374+
time.sleep(0.1)
375+
duration_a = time.perf_counter() - start_a
376+
377+
# Vertex B
378+
start_b = time.perf_counter()
379+
time.sleep(0.02)
380+
duration_b = time.perf_counter() - start_b
381+
382+
cumulative = time.time() - pipeline_start
383+
384+
# Assert
385+
assert duration_b < cumulative / 2, (
386+
f"Vertex B ({duration_b}s) must be much less than cumulative ({cumulative}s)"
387+
)
388+
assert duration_b < duration_a, "Fast vertex B must be shorter than slow vertex A"

src/frontend/package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
"@storybook/react-vite": "^10.1.0",
149149
"@swc/cli": "^0.5.2",
150150
"@swc/core": "^1.6.1",
151+
"@tailwindcss/container-queries": "^0.1.1",
151152
"@tailwindcss/typography": "^0.5.13",
152153
"@testing-library/dom": "^10.4.1",
153154
"@testing-library/jest-dom": "^6.9.1",

0 commit comments

Comments
 (0)