Skip to content

feat: display chat messages for dag-run#1578

Merged
yohamta0 merged 5 commits into
mainfrom
disp-message-hist
Jan 12, 2026
Merged

feat: display chat messages for dag-run#1578
yohamta0 merged 5 commits into
mainfrom
disp-message-hist

Conversation

@yohamta0

@yohamta0 yohamta0 commented Jan 12, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

Release Notes

  • New Features

    • Added chat message history viewing for DAG run steps, including LLM metadata (model, provider, token counts).
    • Introduced new chat tab in DAG status view to browse step-level conversations.
    • Extended support to view messages from steps within sub-DAG runs.
  • Dependencies

    • Added markdown rendering libraries for improved chat message formatting.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This PR adds new API endpoints to retrieve LLM chat messages from DAG run steps, introduces chat message data models across backend and frontend, implements secret masking in executor messages, and develops UI components to display chat history in DAG run details.

Changes

Cohort / File(s) Summary
API Schema & Code Generation
api/v2/api.yaml, api/v2/api.gen.go, ui/src/api/v2/schema.ts
Adds two new GET endpoints for retrieving chat messages from DAG steps and sub-DAG steps. Introduces ChatMessage, ChatMessageMetadata, ChatMessagesResponse, and ChatMessageRole types. Generates corresponding request/response objects, strict handler interfaces, and TypeScript schema definitions.
Backend Executor & Masking
internal/runtime/builtin/chat/executor.go, internal/runtime/builtin/chat/executor_test.go
Adds maskSecretsForProvider function to mask secrets within LLM message content while preserving role and metadata. Includes comprehensive test coverage for nil/empty secrets, multi-secret masking, and metadata preservation.
Backend Service Layer
internal/service/frontend/api/v2/dagruns.go, internal/service/frontend/api/v2/transformer.go
Implements GetDAGRunStepMessages and GetSubDAGRunStepMessages endpoints with validation, message retrieval, and type conversion. Adds toChatMessages helper to convert internal exec.LLMMessage to API ChatMessage types.
Frontend Chat History UI
ui/src/features/dags/components/chat-history/ChatHistoryTab.tsx, ui/src/features/dags/components/chat-history/StepMessagesTable.tsx, ui/src/features/dags/components/chat-history/index.ts
Creates new chat history tab component with step selector and message rendering. Implements StepMessagesTable for displaying expandable messages with metadata, copy-to-clipboard, and role-based styling. Exports ChatHistoryTab from module index.
Frontend Core Components & Config
ui/src/features/dags/components/DAGStatus.tsx, ui/src/components/ui/markdown.tsx, ui/package.json, ui/CLAUDE.md
Extends DAGStatus to include 'chat' tab with chat step detection. Adds compact Markdown renderer component for chat message content. Updates dependencies with react-markdown and remark-gfm. Adds development workflow notice.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: display chat messages for dag-run' accurately summarizes the main objective of the pull request, which adds functionality to display chat messages for DAG runs through new API endpoints and UI components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In @api/v2/api.yaml:
- Around line 2043-2074: The sub-DAG chat messages endpoint description must
mirror the root endpoint by promising an empty array for non-chat steps; update
the description for the sub-DAG path
/dag-runs/{name}/sub-dags/{subDagName}/{dagRunId}/steps/{stepName}/messages (the
GET operation that parallels getDAGRunStepMessages) to append "Returns empty
array for non-chat steps" so the behavior guarantee is consistent across both
endpoints.

In @ui/src/components/ui/markdown.tsx:
- Around line 13-29: The container div rendering Markdown uses cn(...) to build
its className and currently lacks word-wrapping utilities; update the class list
passed into cn (the string array around 'text-xs prose prose-sm ...', used in
the div in markdown.tsx) to include 'break-words' and optionally
'whitespace-normal' so long unbroken tokens will wrap and not overflow the UI.

In @ui/src/features/dags/components/chat-history/ChatHistoryTab.tsx:
- Around line 64-83: The select in ChatHistoryTab.tsx lacks an accessible
label/id and dark-mode + focus styling: add an id (e.g., "step-select") and
aria-label referencing it (or connect a visible label), keep using selectedStep
and setSelectedStep for value/onChange, update className on the select to
include dark-mode variants (e.g., bg-white/dark:bg-surface,
text-foreground/dark:text-foreground,
border-neutral-300/dark:border-neutral-700) and keyboard focus styles (e.g.,
focus:outline-none focus-visible:ring-2 focus-visible:ring-ring
focus-visible:ring-offset-0 or the project’s focus utility), and ensure options
rendered from chatSteps remain unchanged (key/value use node.step.name) so
keyboard users and screen readers can navigate and identify the control; also
preserve isSelectedRunning and Loader2 behavior.
- Around line 22-49: The selectedStep state in ChatHistoryTab is initialized
from the memoized defaultStep so it never updates when defaultStep changes
(e.g., when dagRun.nodes arrive), leaving the select empty or stale; fix by
initializing selectedStep to undefined (or keep as is) and add a useEffect that
watches defaultStep (and/or chatSteps/run id) and calls
setSelectedStep(defaultStep) whenever defaultStep changes or the current
selectedStep is no longer present; update references to defaultStep and
selectedStep in the effect so selection resets appropriately when runs switch.

In @ui/src/features/dags/components/chat-history/StepMessagesTable.tsx:
- Around line 138-151: The StepMessagesTable component renders containers and
message items with hardcoded "bg-white" which breaks dark mode; update the
className usages in the component (the outer container and the per-message div
returned in messages.map inside StepMessagesTable) to include dark-mode variants
(for example replace "bg-white" with "bg-white dark:bg-neutral-900" or the
project’s approved dark background token) and ensure any roleConfig.borderColor
still reads correctly against the dark background; adjust any additional utility
classes in the same JSX block if needed so text and border contrast remain
accessible in dark mode.
🧹 Nitpick comments (7)
internal/runtime/builtin/chat/executor_test.go (1)

477-558: Good test coverage with one minor improvement opportunity.

The test cases cover important scenarios well. However, the metadata preservation check at lines 553-555 only verifies the first message when metadata is present, but the test case "preserves role and metadata" has only one message. Consider adding a test case with multiple messages where metadata exists on a non-first message to ensure metadata is correctly preserved across all messages.

💡 Optional: Enhance metadata preservation test
 		{
 			name:    "preserves role and metadata",
 			secrets: map[string]string{"SECRET": "xyz"},
 			messages: []exec.LLMMessage{
+				{Role: exec.RoleUser, Content: "First message"},
 				{
 					Role:     exec.RoleAssistant,
 					Content:  "Value: xyz",
 					Metadata: &exec.LLMMessageMetadata{Model: "gpt-4"},
 				},
 			},
-			wantMasked: []string{"Value: *******"},
+			wantMasked: []string{"First message", "Value: *******"},
 		},

Then update the metadata check:

 			// Verify metadata is preserved
-			if len(tt.messages) > 0 && tt.messages[0].Metadata != nil {
-				assert.Equal(t, tt.messages[0].Metadata, result[0].Metadata)
+			for i, msg := range tt.messages {
+				if msg.Metadata != nil {
+					assert.Equal(t, msg.Metadata, result[i].Metadata)
+				}
 			}
ui/src/features/dags/components/DAGStatus.tsx (1)

277-290: Tab reset logic is good; consider boolean-normalizing hasChatSteps for readability.
const hasChatSteps = !!dagRun.nodes?.some(...) avoids boolean | undefined (current code works, but this is cleaner).

api/v2/api.yaml (1)

3260-3318: Schema set is solid; consider minimums for token counts.
If you want stronger validation, add minimum: 0 for promptTokens, completionTokens, totalTokens.

ui/src/components/ui/markdown.tsx (1)

31-66: Using inline prop is not reliable in react-markdown v10 — check for language pattern instead.

Fenced code blocks without a language specification do have no className, so !codeClassName would incorrectly treat them as inline. However, the inline prop was removed/changed in react-markdown v10 and causes TypeScript errors (see GitHub issue #776).

Instead, detect block code by checking for the language pattern: const isInline = !/^language-/.test(codeClassName || ''). This aligns with how react-markdown assigns language classes to fenced blocks.

ui/src/features/dags/components/chat-history/StepMessagesTable.tsx (2)

86-100: Initial state uses stale data reference.

The expandedIndexes initial value is computed from messages.length - 1, but at initialization, messages is [] (data not yet fetched), resulting in new Set([-1]). While the useEffect corrects this when messages arrive, consider initializing with an empty set.

Suggested fix
-  // Only last message expanded by default
-  const [expandedIndexes, setExpandedIndexes] = useState<Set<number>>(
-    new Set([messages.length - 1])
-  );
+  // Track expanded message indexes; useEffect expands the latest when messages arrive
+  const [expandedIndexes, setExpandedIndexes] = useState<Set<number>>(new Set());

111-119: Silent failure on clipboard error.

The empty catch block provides no feedback when clipboard access fails. Consider a brief visual indicator or console warning for debugging.

Optional: Add minimal feedback
   const handleCopy = async (content: string, index: number) => {
     try {
       await navigator.clipboard.writeText(content);
       setCopiedIndex(index);
       setTimeout(() => setCopiedIndex(null), 2000);
-    } catch {
-      // Clipboard access denied
+    } catch (err) {
+      console.warn('Clipboard access denied:', err);
     }
   };
api/v2/api.gen.go (1)

284-340: Chat message response model is fine; avoid messages: null at runtime. ChatMessagesResponse.Messages is a non-omitempty slice, so if handlers leave it nil, clients will see null instead of []. Recommend ensuring handlers always initialize to an empty slice when there are no messages.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1428cbd and 7ab18ed.

⛔ Files ignored due to path filters (1)
  • ui/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • api/v2/api.gen.go
  • api/v2/api.yaml
  • internal/runtime/builtin/chat/executor.go
  • internal/runtime/builtin/chat/executor_test.go
  • internal/service/frontend/api/v2/dagruns.go
  • internal/service/frontend/api/v2/transformer.go
  • ui/CLAUDE.md
  • ui/package.json
  • ui/src/api/v2/schema.ts
  • ui/src/components/ui/markdown.tsx
  • ui/src/features/dags/components/DAGStatus.tsx
  • ui/src/features/dags/components/chat-history/ChatHistoryTab.tsx
  • ui/src/features/dags/components/chat-history/StepMessagesTable.tsx
  • ui/src/features/dags/components/chat-history/index.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Backend entrypoint in cmd/ orchestrates the scheduler and CLI; runtime, persistence, and service layers sit under internal/* (for example internal/runtime, internal/persistence)
Keep Go files gofmt/goimports clean; use tabs, PascalCase for exported symbols (SchedulerClient), lowerCamelCase for locals, and Err... names for package-level errors
Repository linting relies on golangci-lint; prefer idiomatic Go patterns, minimal global state, and structured logging helpers in internal/common

Files:

  • internal/runtime/builtin/chat/executor.go
  • internal/service/frontend/api/v2/transformer.go
  • internal/runtime/builtin/chat/executor_test.go
  • internal/service/frontend/api/v2/dagruns.go
  • api/v2/api.gen.go
ui/**/*.{ts,tsx,jsx,js}

📄 CodeRabbit inference engine (ui/CLAUDE.md)

ui/**/*.{ts,tsx,jsx,js}: Use developer-centric UI design with high information density, minimal whitespace, compact components, and no unnecessary decorations
Support both light and dark modes for all UI components using Tailwind CSS class pairs like dark:bg-slate-700
NEVER use full-page loading overlays or LoadingIndicator components that hide content - show stale data while fetching updates instead
Use compact modal design with small headers, minimal padding (p-2 or p-3), tight spacing, and support keyboard navigation (arrows, enter, escape)
Use small heights for form elements: select boxes h-7 or smaller, buttons h-7 or h-8, inputs with compact padding (py-0.5 or py-1)
Minimize row heights in tables and lists while maintaining readability, merge related columns, and always handle long text with whitespace-normal break-words
Use consistent metadata styling with bg-slate-200 dark:bg-slate-700 backgrounds and maintain text hierarchy with primary/secondary/muted text colors
Use flexbox-first layouts with min-h-0 and overflow-hidden to prevent layout breaks, account for fixed elements when setting heights
Maintain keyboard navigation support in all interactive components with appropriate focus indicators and ARIA labels

Files:

  • ui/src/features/dags/components/chat-history/index.ts
  • ui/src/features/dags/components/DAGStatus.tsx
  • ui/src/components/ui/markdown.tsx
  • ui/src/features/dags/components/chat-history/StepMessagesTable.tsx
  • ui/src/features/dags/components/chat-history/ChatHistoryTab.tsx
  • ui/src/api/v2/schema.ts
ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

ui/**/*.{ts,tsx}: The React + TypeScript frontend resides in ui/, with production bundles copied to internal/service/frontend/assets by make ui
UI code follows ESLint + Prettier (2-space indent) and Tailwind utilities; name React components in PascalCase (JobList.tsx) and hooks with use* (useJobs.ts)

Files:

  • ui/src/features/dags/components/chat-history/index.ts
  • ui/src/features/dags/components/DAGStatus.tsx
  • ui/src/components/ui/markdown.tsx
  • ui/src/features/dags/components/chat-history/StepMessagesTable.tsx
  • ui/src/features/dags/components/chat-history/ChatHistoryTab.tsx
  • ui/src/api/v2/schema.ts
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Co-locate Go tests as *_test.go; favour table-driven cases and cover failure paths
Use stretchr/testify/require and shared fixtures from internal/test instead of duplicating mocks

Files:

  • internal/runtime/builtin/chat/executor_test.go
{api/v1,api/v2}/**/*.{proto,yaml,yml,json}

📄 CodeRabbit inference engine (AGENTS.md)

API definitions live in api/v1 and api/v2; generated server stubs land in internal/service, while matching TypeScript clients flow into ui/src/api

Files:

  • api/v2/api.yaml
🧠 Learnings (9)
📚 Learning: 2025-12-04T10:34:01.045Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: ui/CLAUDE.md:0-0
Timestamp: 2025-12-04T10:34:01.045Z
Learning: Applies to ui/**/*.{ts,tsx,jsx,js} : Minimize row heights in tables and lists while maintaining readability, merge related columns, and always handle long text with `whitespace-normal break-words`

Applied to files:

  • ui/src/components/ui/markdown.tsx
  • ui/src/features/dags/components/chat-history/StepMessagesTable.tsx
📚 Learning: 2025-12-04T10:34:01.045Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: ui/CLAUDE.md:0-0
Timestamp: 2025-12-04T10:34:01.045Z
Learning: Applies to ui/**/Makefile : Ensure frontend builds without errors by running `make ui` before committing changes

Applied to files:

  • ui/CLAUDE.md
📚 Learning: 2025-12-04T10:34:17.062Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.062Z
Learning: Frontend workflows: `cd ui && pnpm dev` for hot reload, `pnpm build` for production bundles, `pnpm lint` to auto-fix TypeScript/React style issues

Applied to files:

  • ui/CLAUDE.md
  • ui/package.json
📚 Learning: 2025-12-04T10:34:01.045Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: ui/CLAUDE.md:0-0
Timestamp: 2025-12-04T10:34:01.045Z
Learning: Applies to ui/**/.gitignore,** : Use pnpm for frontend package management instead of npm or yarn

Applied to files:

  • ui/CLAUDE.md
📚 Learning: 2025-12-04T10:34:17.062Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.062Z
Learning: Applies to ui/**/*.{ts,tsx} : The React + TypeScript frontend resides in `ui/`, with production bundles copied to `internal/service/frontend/assets` by `make ui`

Applied to files:

  • ui/CLAUDE.md
  • ui/package.json
📚 Learning: 2025-12-04T10:34:17.062Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.062Z
Learning: `make run` starts the Go scheduler and serves the compiled UI (fails fast if `ui/dist` is missing)

Applied to files:

  • ui/CLAUDE.md
📚 Learning: 2025-12-04T10:34:01.045Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: ui/CLAUDE.md:0-0
Timestamp: 2025-12-04T10:34:01.045Z
Learning: Applies to ui/**/*.{ts,tsx,jsx,js} : Use developer-centric UI design with high information density, minimal whitespace, compact components, and no unnecessary decorations

Applied to files:

  • ui/CLAUDE.md
📚 Learning: 2025-12-04T10:34:17.062Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.062Z
Learning: Verify `make lint` and `make test` locally; include unit or integration tests whenever behaviour or APIs change

Applied to files:

  • ui/CLAUDE.md
📚 Learning: 2025-12-04T10:34:17.062Z
Learnt from: CR
Repo: dagu-org/dagu PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T10:34:17.062Z
Learning: Applies to ui/**/*.{ts,tsx} : UI code follows ESLint + Prettier (2-space indent) and Tailwind utilities; name React components in PascalCase (`JobList.tsx`) and hooks with `use*` (`useJobs.ts`)

Applied to files:

  • ui/CLAUDE.md
🧬 Code graph analysis (7)
internal/runtime/builtin/chat/executor.go (3)
internal/core/llm.go (1)
  • LLMMessage (98-103)
internal/runtime/context.go (1)
  • GetDAGContext (50-52)
internal/llm/types.go (2)
  • Role (8-8)
  • ChatRequest (126-143)
ui/src/features/dags/components/DAGStatus.tsx (4)
ui/src/api/v2/schema.ts (1)
  • components (1265-2210)
ui/src/components/ui/tabs.tsx (1)
  • Tab (49-49)
ui/src/features/dags/components/chat-history/ChatHistoryTab.tsx (1)
  • ChatHistoryTab (12-99)
ui/src/features/dags/components/chat-history/index.ts (1)
  • ChatHistoryTab (1-1)
internal/service/frontend/api/v2/transformer.go (2)
internal/core/llm.go (1)
  • LLMMessage (98-103)
api/v2/api.gen.go (3)
  • ChatMessage (285-294)
  • ChatMessageRole (297-297)
  • ChatMessageMetadata (300-315)
ui/src/components/ui/markdown.tsx (1)
ui/src/lib/utils.ts (1)
  • cn (4-6)
internal/runtime/builtin/chat/executor_test.go (3)
internal/runtime/context.go (1)
  • WithSecrets (38-38)
internal/core/llm.go (1)
  • LLMMessage (98-103)
internal/llm/types.go (4)
  • Role (8-8)
  • RoleUser (14-14)
  • RoleSystem (12-12)
  • RoleAssistant (16-16)
ui/src/features/dags/components/chat-history/StepMessagesTable.tsx (5)
api/v2/api.gen.go (1)
  • ChatMessageRole (297-297)
ui/src/contexts/AppBarContext.ts (1)
  • AppBarContext (11-21)
ui/src/hooks/api.ts (1)
  • useQuery (28-28)
ui/src/lib/utils.ts (1)
  • cn (4-6)
ui/src/components/ui/markdown.tsx (1)
  • Markdown (11-71)
ui/src/api/v2/schema.ts (1)
api/v2/api.gen.go (1)
  • ChatMessageRole (297-297)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test on ubuntu-latest
  • GitHub Check: Build
🔇 Additional comments (28)
internal/runtime/builtin/chat/executor_test.go (1)

464-475: LGTM! Well-structured test helper.

The helper correctly handles nil secrets and builds the context with proper "KEY=value" format expected by exec.WithSecrets.

ui/package.json (1)

106-109: LGTM! Dependencies are appropriate for the new Markdown rendering feature.

The react-markdown ^10.1.0 and remark-gfm ^4.0.1 versions are compatible with React 19 and correctly placed in runtime dependencies.

ui/src/features/dags/components/chat-history/index.ts (1)

1-1: LGTM!

Clean barrel export following standard module organization patterns.

internal/service/frontend/api/v2/transformer.go (1)

304-331: LGTM! Clean transformer implementation.

The function follows the established patterns in this file:

  • Proper nil handling with empty slice return
  • Pre-allocated slice with correct capacity
  • Consistent use of ptrOf for optional metadata fields

The direct cast api.ChatMessageRole(msg.Role) works because both types are string-based.

internal/runtime/builtin/chat/executor.go (2)

249-273: LGTM! Well-implemented secret masking for LLM provider calls.

The function correctly:

  • Returns early when no secrets exist (avoiding unnecessary processing)
  • Preserves message Role and Metadata while only masking Content
  • Creates a new slice rather than mutating the input

291-295: Verify: Intentional design to save unmasked messages.

The code masks messages only for the LLM provider call (line 295), while savedMessages (line 356) stores the original unmasked allMessages. This means:

  • Secrets are protected from external LLM APIs ✓
  • Chat history displayed in UI will show unmasked content

Please confirm this is the intended behavior - users will see their original messages (including any secrets they typed) in the chat history UI.

ui/src/features/dags/components/DAGStatus.tsx (2)

12-43: Chat tab wiring + StatusTab update looks consistent.
Imports and StatusTab union update are straightforward.


322-441: Conditional Chat tab + content render is clean and avoids showing non-functional UI.

internal/service/frontend/api/v2/dagruns.go (2)

720-725: No action needed. node.Status.String() output exactly matches the OpenAPI NodeStatusLabel enum values (lowercase with underscores, e.g., "succeeded", "not_started"). The code is correct as written.


677-775: No changes needed. The code already handles missing messages correctly. ReadStepMessages() returns (nil, nil) when the message file doesn't exist (per the test cases ReadNonExistentStepMessages and WriteEmptyMessages), so the handler never executes the error path for this scenario. The response correctly converts the nil messages to an empty array via toChatMessages(), matching the OpenAPI contract ("Returns empty array for non-chat steps").

If other error types (e.g., file read or JSON unmarshal failures) should also return 200 with empty messages rather than 500, that would be a separate concern worth addressing. The suggested detection of non-chat steps via ExecutorConfig.Type is also incomplete without specifying how to reliably identify non-chat step types from the available node data.

Likely an incorrect or invalid review comment.

ui/src/features/dags/components/chat-history/StepMessagesTable.tsx (6)

1-7: LGTM!

Imports are clean and appropriately organized. Good use of the custom useQuery hook and typed schema imports.


9-18: LGTM!

Well-defined interface with clear prop names. The sub-DAG context props (subDAGRunId, rootDagName, rootDagRunId) are appropriately optional.


20-30: LGTM!

Role configuration with semantic border colors is a clean pattern. The fallback defaultRoleConfig handles unknown roles gracefully.


121-136: LGTM!

Loading and empty states are compact and appropriate. The conditional isLoading && messages.length === 0 correctly shows stale data while fetching updates, aligning with coding guidelines.


152-180: LGTM!

The header row implementation is well-structured:

  • Compact styling with px-2 py-1
  • Accessible button with type="button"
  • Smart collapsed preview with truncation
  • Proper rotation animation for the chevron

182-218: LGTM!

Expanded content section is well-implemented:

  • Good use of Markdown component for rich content rendering
  • Metadata display is informative and compact
  • Copy button with visual feedback is a nice UX touch
  • e.stopPropagation() correctly prevents toggle when clicking copy
ui/src/api/v2/schema.ts (2)

1312-1344: LGTM!

The ChatMessage-related schemas are well-structured:

  • ChatMessage with role, content, and optional metadata follows standard LLM conversation patterns
  • ChatMessageMetadata captures useful token usage and model info
  • ChatMessagesResponse appropriately includes step status context and hasMore for polling scenarios

5870-5875: LGTM!

The ChatMessageRole enum values (system, user, assistant, tool) align with standard LLM API conventions used by OpenAI, Anthropic, and others.

api/v2/api.gen.go (10)

31-38: ChatMessageRole enum values look consistent and usable. The typed constants for "assistant" | "system" | "tool" | "user" are a good addition for compile-time safety.


1688-1693: New params structs are consistent with the rest of the API. Optional remoteNode query param matches existing endpoint patterns.

Also applies to: 1787-1792


2383-2386: Server interface expansion looks correct; confirm auth parity with logs. The two new handler methods match the new routes; please ensure the implementation applies the same authn/z + audit expectations as /log endpoints.

Also applies to: 2410-2412


2668-2672: Unimplemented stubs are correctly generated.

Also applies to: 2722-2726


4043-4103: Wrapper binding for new endpoints looks correct. Path params and remoteNode query binding follow the established pattern and should integrate cleanly with middleware.

Also applies to: 4681-4750


6563-6565: Route registrations are correct and non-conflicting. The new .../messages GET routes are added alongside existing step log routes in HandlerWithOptions.

Also applies to: 6590-6592


7740-7779: Request/response object types for strict mode look consistent. 200 returns ChatMessagesResponse, 404/default follow existing conventions.

Also applies to: 8133-8173


9891-9894: StrictServerInterface additions are correctly wired.

Also applies to: 9918-9920


10715-10742: strictHandler methods correctly delegate to StrictServerInterface. Middleware hook names and request object casting match the generated pattern.

Also applies to: 10997-11025


12168-12442: Generated swaggerSpec update is expected; avoid manual edits here. Just ensure api/v2/api.yaml is the source of truth and the generator version is consistent across environments.

Comment thread api/v2/api.yaml
Comment thread ui/CLAUDE.md
Comment thread ui/src/components/ui/markdown.tsx
Comment thread ui/src/features/dags/components/chat-history/ChatHistoryTab.tsx
Comment thread ui/src/features/dags/components/chat-history/ChatHistoryTab.tsx
Comment thread ui/src/features/dags/components/chat-history/StepMessagesTable.tsx
@yohamta0 yohamta0 merged commit bfbfc5a into main Jan 12, 2026
7 of 8 checks passed
@yohamta0 yohamta0 deleted the disp-message-hist branch January 12, 2026 16:58
@codecov

codecov Bot commented Jan 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.23529% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.79%. Comparing base (1557b14) to head (61021b9).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
internal/runtime/builtin/chat/executor.go 88.23% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #1578   +/-   ##
=======================================
  Coverage   64.78%   64.79%           
=======================================
  Files         255      255           
  Lines       28380    28396   +16     
=======================================
+ Hits        18387    18400   +13     
- Misses       8346     8348    +2     
- Partials     1647     1648    +1     
Files with missing lines Coverage Δ
internal/runtime/builtin/chat/executor.go 50.26% <88.23%> (+4.02%) ⬆️

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1428cbd...61021b9. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant