Skip to content

feat: pipeline builder UI — visual config wizard (#8)#8

Merged
CIKR-Repos merged 2 commits intomainfrom
feat/pipeline-builder-ui
Feb 18, 2026
Merged

feat: pipeline builder UI — visual config wizard (#8)#8
CIKR-Repos merged 2 commits intomainfrom
feat/pipeline-builder-ui

Conversation

@CIKR-Repos
Copy link
Owner

@CIKR-Repos CIKR-Repos commented Feb 18, 2026

Pipeline Builder UI

What

  • Visual pipeline configuration (source → chunking → embedding → storage)
  • Step-by-step wizard interface
  • Model selection per pipeline step
  • Pipeline status monitoring
  • Pipeline service with API integration

Tech

  • Angular 21 Signals + Tailwind CSS
  • Standalone components following existing patterns
  • QueryEngineService fixes

Files Changed

  • Pipeline page component (template + logic)
  • Pipeline service for API calls
  • QueryEngineService minor fixes
  • Feature doc

PR #8 of 10 — Pipeline Builder UI

Summary by Sourcery

Introduce a visual pipeline builder UI with configurable RAG stages and supporting backend/API integration updates.

New Features:

  • Add a drag-and-drop pipeline page that lets users configure pipeline blocks and their parameters per project.
  • Introduce a PipelineService to load, save, and manage pipeline configuration, documents, models, and chunk previews via the API.

Enhancements:

  • Update QueryEngineService to include the current user message when building chat history for both sync and streaming queries.
  • Enable TailwindCSS and Angular CDK drag-and-drop to support the new pipeline builder experience.

Documentation:

  • Add a feature document describing the pipeline builder UI, pipeline blocks, chunk preview behavior, and related API endpoints.

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 18, 2026

Reviewer's Guide

Implements a visual, step-based pipeline builder UI with drag-and-drop blocks and a backing PipelineService that loads/saves pipeline config and related data via APIs, wires it into the pipeline route, and fixes QueryEngineService to include the latest user message when building chat history.

Sequence diagram for loading and saving pipeline configuration

sequenceDiagram
  actor User
  participant Router as AngularRouter
  participant PipelineComponent
  participant PipelineService
  participant HttpClient
  participant ApiServer

  User->>Router: Navigate to /projects/:projectId/pipeline
  Router->>PipelineComponent: Create component instance
  PipelineComponent->>PipelineComponent: ngOnInit()
  PipelineComponent->>PipelineService: loadPipeline(projectId)
  PipelineService->>PipelineService: isLoading = true
  PipelineService->>HttpClient: GET /api/projects/projectId/pipelines
  HttpClient-->>PipelineService: PipelineResponse[]
  PipelineService->>PipelineService: pipeline, config, savedConfig signals updated
  PipelineService->>HttpClient: GET /api/projects/projectId/documents
  HttpClient-->>PipelineService: DocumentInfo[]
  PipelineService->>PipelineService: documents signal updated
  PipelineService->>HttpClient: GET /api/models
  HttpClient-->>PipelineService: ModelSelection
  PipelineService->>PipelineService: models signal updated
  PipelineService->>PipelineService: isLoading = false

  User->>PipelineComponent: Edit config fields
  PipelineComponent->>PipelineService: updateConfig(partialConfig)
  PipelineService->>PipelineService: config signal updated
  PipelineService->>PipelineService: hasUnsavedChanges computed true

  User->>PipelineComponent: Click Save
  PipelineComponent->>PipelineService: savePipeline(projectId)
  PipelineService->>PipelineService: isSaving = true, saveError = null
  PipelineService->>HttpClient: PUT /api/projects/projectId/pipelines/pipelineId
  HttpClient-->>PipelineService: Updated PipelineResponse
  PipelineService->>PipelineService: pipeline, savedConfig, config signals updated
  PipelineService->>PipelineService: isSaving = false
Loading

Sequence diagram for chunk preview loading in pipeline builder

sequenceDiagram
  actor User
  participant PipelineComponent
  participant PipelineService
  participant HttpClient
  participant ApiServer

  User->>PipelineComponent: Select document for chunk preview
  PipelineComponent->>PipelineService: loadChunkPreview(projectId, documentId)
  PipelineService->>PipelineService: Read current config (chunkSize, chunkOverlap)
  PipelineService->>HttpClient: GET /api/projects/projectId/documents/documentId/chunks
  note right of HttpClient: Query params
  HttpClient-->>ApiServer: chunkSize, chunkOverlap, page=1, pageSize=3
  ApiServer-->>HttpClient: ChunkPreviewResponse
  HttpClient-->>PipelineService: ChunkPreviewResponse
  PipelineService->>PipelineService: chunkPreview signal updated
  PipelineService-->>PipelineComponent: Updated chunk preview state rendered
Loading

Sequence diagram for updated QueryEngineService chat history building

sequenceDiagram
  participant Client
  participant QueryEngineService
  participant Memory as ConversationMemory
  participant KernelFactory
  participant ChatService as IChatCompletionService

  Client->>QueryEngineService: QueryAsync(sessionId, userMessage, sources, models)
  QueryEngineService->>Memory: GetConversationWindowAsync(sessionId)
  Memory-->>QueryEngineService: conversationHistory
  QueryEngineService->>KernelFactory: BuildChatKernel(models.ChatModel)
  KernelFactory-->>QueryEngineService: Kernel
  QueryEngineService->>QueryEngineService: BuildChatHistory(conversationHistory, sources, userMessage)
  QueryEngineService->>ChatService: GetChatMessageContentAsync(chatHistory)
  ChatService-->>QueryEngineService: ChatResponseContent
  QueryEngineService-->>Client: ChatResponse

  Client->>QueryEngineService: QueryStreamAsync(sessionId, userMessage, sources, models)
  QueryEngineService->>Memory: GetConversationWindowAsync(sessionId)
  Memory-->>QueryEngineService: conversationHistory
  QueryEngineService->>KernelFactory: BuildChatKernel(models.ChatModel)
  KernelFactory-->>QueryEngineService: Kernel
  QueryEngineService->>QueryEngineService: BuildChatHistory(conversationHistory, sources, userMessage)
  QueryEngineService->>ChatService: GetStreamingChatMessageContents(chatHistory)
  ChatService-->>QueryEngineService: ChatStreamChunk*
  QueryEngineService-->>Client: ChatStreamChunk*
Loading

Class diagram for PipelineComponent and PipelineService

classDiagram
  class PipelineConfig {
    +number chunkSize
    +number chunkOverlap
    +string chunkingStrategy
    +string embeddingModel
    +number embeddingDimensions
    +string retrievalStrategy
    +number topK
    +number scoreThreshold
    +string generationModel
    +number temperature
    +number maxTokens
    +string systemPrompt
  }

  class PipelineResponse {
    +string id
    +string projectId
    +string name
    +string description
    +PipelineConfig config
    +string status
    +string createdAt
    +string updatedAt
  }

  class DocumentInfo {
    +string id
    +string fileName
    +string fileType
    +number fileSize
    +string status
  }

  class ChunkPreviewItem {
    +string content
    +number tokenCount
    +number index
  }

  class ChunkPreviewResponse {
    +ChunkPreviewItem[] chunks
    +number totalCount
    +number page
    +number pageSize
  }

  class ModelSelection {
    +string embeddingModel
    +number embeddingDimensions
    +string chatModel
    +number maxTokensPerRequest
    +number maxDocumentsPerProject
  }

  class PipelineService {
    -HttpClient http
    +pipeline signal~PipelineResponse|
    +config signal~PipelineConfig|
    +savedConfig signal~PipelineConfig|
    +documents signal~DocumentInfo[]|
    +models signal~ModelSelection|
    +chunkPreview signal~ChunkPreviewResponse|
    +isSaving signal~boolean|
    +isLoading signal~boolean|
    +saveError signal~string|
    +hasUnsavedChanges computed~boolean|
    +loadPipeline(projectId string) Promise~void|
    +savePipeline(projectId string) Promise~void|
    +resetDefaults() void
    +updateConfig(partial PipelineConfig) void
    +loadChunkPreview(projectId string, documentId string) Promise~void|
  }

  class PipelineComponent {
    -ActivatedRoute route
    +PipelineService svc
    -string projectId
    +ngOnInit() void
    +onDrop(event CdkDragDrop) void
    +save() void
    +blockClass(block PipelineBlock) string
    +blockIconBg(block PipelineBlock) string
    +blockTypeBadge(block PipelineBlock) string
    +blockSummary(block PipelineBlock) string
    +onConfigChange(blockId string, key string, event Event) void
    +onConfigChangeNum(blockId string, key string, event Event) void
    +onConfigChangeFloat(blockId string, key string, event Event) void
    +onConfigChangeBool(blockId string, key string, event Event) void
  }

  class PipelineBlock {
    +string id
    +BlockType type
    +Record config
  }

  class BlockType {
  }

  PipelineService --> PipelineConfig
  PipelineService --> PipelineResponse
  PipelineService --> DocumentInfo
  PipelineService --> ChunkPreviewResponse
  PipelineService --> ModelSelection
  PipelineComponent --> PipelineService
  PipelineComponent --> PipelineBlock
  PipelineBlock --> BlockType
Loading

File-Level Changes

Change Details Files
Replace placeholder pipeline page with an interactive drag-and-drop pipeline builder wired to a new PipelineService.
  • Convert PipelineComponent to use Angular CDK drag/drop for reordering pipeline blocks and Tailwind-based visual styling per block type.
  • Inject ActivatedRoute and PipelineService, loading the pipeline for the current projectId on init.
  • Add handlers for saving pipelines, updating block selection and visual state, and mapping block config fields into human-readable summaries.
  • Wire generic config change handlers (string/number/float/bool) to delegate updates to the service.
client/src/app/pages/pipeline/pipeline.ts
client/src/app/pages/pipeline/pipeline.html
Introduce a dedicated PipelineService using Angular signals to manage pipeline config, documents, models, and chunk preview via backend APIs.
  • Define PipelineConfig, PipelineResponse, and related DTO interfaces along with DEFAULT_CONFIG.
  • Use Angular signals for pipeline state (pipeline, config, documents, models, chunkPreview) and derived hasUnsavedChanges.
  • Implement loadPipeline to fetch existing pipeline, merge with defaults, load documents and available models, and manage loading state.
  • Implement savePipeline to persist config via PUT, update local state, and surface save errors and saving state.
  • Provide helpers for resetting/updating config and loading chunk previews with current chunking parameters.
client/src/app/features/pipeline-builder/pipeline.service.ts
Fix QueryEngineService so chat history construction includes the current user message for both sync and streaming queries.
  • Update QueryAsync to pass userMessage into BuildChatHistory.
  • Update QueryStreamAsync to pass userMessage into BuildChatHistory for streaming responses as well.
src/PipeRAG.Infrastructure/Services/QueryEngineService.cs
Add styling and dependency wiring needed for the new UI, and document the new pipeline builder feature.
  • Add @angular/cdk dependency for drag-and-drop support.
  • Enable Tailwind via import in the global styles file for utility-based styling used by the pipeline UI.
  • Capture the feature design and endpoints in a feature doc covering the pipeline builder components, blocks, chunk preview, and related API usage.
client/package.json
client/package-lock.json
client/src/styles.scss
docs/features/pr-008-pipeline-builder-ui.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@CIKR-Repos
Copy link
Owner Author

@copilot please review this PR

Copy link

Copilot AI commented Feb 18, 2026

@CIKR-Repos I've opened a new pull request, #9, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The PipelineComponent imports PipelineService from ./pipeline.service, but the new service was added under features/pipeline-builder/pipeline.service.ts; double-check that the import path and file location are aligned so the component actually uses the intended service.
  • Since PipelineService is already marked providedIn: 'root', adding it again in PipelineComponent.providers will create a separate instance and can lead to confusing state; consider removing the component-level provider unless you explicitly need an isolated instance.
  • The numeric config change handlers (onConfigChangeNum and onConfigChangeFloat) directly use parseInt/parseFloat without handling NaN, which can push invalid values into the config; consider guarding against empty/invalid input and either reverting to the previous value or using a safe default.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `PipelineComponent` imports `PipelineService` from `./pipeline.service`, but the new service was added under `features/pipeline-builder/pipeline.service.ts`; double-check that the import path and file location are aligned so the component actually uses the intended service.
- Since `PipelineService` is already marked `providedIn: 'root'`, adding it again in `PipelineComponent.providers` will create a separate instance and can lead to confusing state; consider removing the component-level provider unless you explicitly need an isolated instance.
- The numeric config change handlers (`onConfigChangeNum` and `onConfigChangeFloat`) directly use `parseInt/parseFloat` without handling `NaN`, which can push invalid values into the config; consider guarding against empty/invalid input and either reverting to the previous value or using a safe default.

## Individual Comments

### Comment 1
<location> `client/src/app/pages/pipeline/pipeline.ts:76-78` </location>
<code_context>
+    this.svc.updateBlockConfig(blockId, key, el.value);
+  }
+
+  onConfigChangeNum(blockId: string, key: string, event: Event) {
+    const el = event.target as HTMLInputElement;
+    this.svc.updateBlockConfig(blockId, key, parseInt(el.value, 10));
+  }
+
</code_context>

<issue_to_address>
**issue:** Handle NaN cases when parsing numeric config values from inputs.

If the input is cleared or contains non-numeric characters, `parseInt`/`parseFloat` will return `NaN`, which will then be stored in the config and may break UI or backend logic. Consider coercing empty values to the previous/default value, clamping to a safe fallback, or skipping the update when the parsed value is `NaN`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@CIKR-Repos CIKR-Repos merged commit 9522c74 into main Feb 18, 2026
1 check passed
@CIKR-Repos CIKR-Repos deleted the feat/pipeline-builder-ui branch February 18, 2026 04:03
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.

2 participants