Skip to content

Extend FormArtifact to support wizard-style inputs & migrate Deep Research to chat-based architecture #2223

@tomsmith8

Description

@tomsmith8

Summary

Extend FormContent to support wizard-style inputs (text, single_choice, multiple_choice), then migrate the Deep Research architecture generation feature to use ChatMessage + FORM artifacts instead of StakworkRun.result/feedback.

This unifies the pattern: when AI wants user input, it creates a FORM artifact - same rendering in task chat and architecture generation.

Key Decisions

  • Storage: Add ChatMessage relation directly to Feature (new schema relation)
  • Migration: No data migration - new system only for new generations
  • Rollout: Feature flag NEXT_PUBLIC_FEATURE_CHAT_ARCHITECTURE

Implementation Plan

Phase 1: Extend FormContent Types

File: src/lib/chat.ts

// New input types
type FormInputType = "text" | "single_choice" | "multiple_choice";

interface FormInput {
  id: string;
  question: string;
  type: FormInputType;
  options?: string[];
  required?: boolean;
  placeholder?: string;
}

// Extend FormContent (backwards compatible)
interface FormContent {
  actionText: string;           // Existing - intro/title
  webhook: string;              // Existing - callback URL
  options: Option[];            // Existing - button options

  // New wizard fields (optional for backwards compat)
  inputs?: FormInput[];
  submitLabel?: string;
  showReview?: boolean;
  allowCustomText?: boolean;
}

// Response structure for wizard submissions
interface FormResponse {
  answers: Record<string, { selections?: string[]; text?: string }>;
  formatted: string;  // "Q: ... A: ..." format
}

Phase 2: Create Shared WizardForm Component

New file: src/components/ui/wizard-form/index.tsx

Extract wizard logic from ClarifyingQuestionsPreview into a reusable component:

  • Props: inputs: FormInput[], onSubmit: (response: FormResponse) => void, isLoading?: boolean
  • Features: step navigation, progress bar, review step, text/choice inputs
  • Reuse existing styling and UX patterns from ClarifyingQuestionsPreview

Phase 3: Extend FormArtifact Component

File: src/app/w/[slug]/task/[...taskParams]/artifacts/form.tsx

Detect wizard-style forms and render appropriately:

export function FormArtifact({ messageId, artifact, onAction, ... }) {
  const content = artifact.content as FormContent;
  const hasWizardInputs = content.inputs && content.inputs.length > 0;

  if (hasWizardInputs) {
    return (
      <WizardForm
        inputs={content.inputs}
        introText={content.actionText}
        onSubmit={(response) => onAction(messageId, response, content.webhook)}
        isLoading={isDisabled}
      />
    );
  }

  // Existing button-style form rendering
  return <ButtonForm ... />;
}

Phase 4: Database Schema Changes

File: prisma/schema.prisma

Add ChatMessage relation to Feature:

model Feature {
  // ... existing fields

  // Architecture generation conversation
  architectureMessages  ChatMessage[]  @relation("FeatureArchitectureMessages")
}

model ChatMessage {
  // ... existing fields

  // Optional: link to feature for architecture conversations
  featureId    String?   @map("feature_id")
  feature      Feature?  @relation("FeatureArchitectureMessages", fields: [featureId], references: [id])
}

Run: npx prisma migrate dev --name add-feature-architecture-messages


Phase 5: Create Architecture Conversation API

New file: src/app/api/features/[featureId]/architecture/messages/route.ts

  • GET - fetch architecture conversation messages
  • POST - create new message (user response to wizard)

New file: src/services/architecture-conversation.ts

  • getArchitectureMessages(featureId)
  • createArchitectureMessage(featureId, params)
  • submitWizardResponse(messageId, response)

Phase 6: Update Stakwork Webhook Handler

File: src/app/api/webhook/stakwork/response/route.ts

When Stakwork returns clarifying questions:

  1. Detect tool_use: "ask_clarifying_questions" response
  2. Transform to FormContent with inputs array
  3. Create ChatMessage with role: ASSISTANT and FORM artifact
  4. Link to Feature via featureId
  5. Broadcast via Pusher

Phase 7: Update AITextareaSection

File: src/components/features/AITextareaSection.tsx

const useChatBasedArchitecture = useFeatureFlag('CHAT_ARCHITECTURE');

if (useChatBasedArchitecture) {
  // Use new ChatMessage-based flow
  // Fetch messages via useArchitectureMessages(featureId)
} else {
  // Existing StakworkRun-based flow
}

New hook: src/hooks/useArchitectureMessages.ts


Phase 8: Add Feature Flag

File: src/lib/feature-flags.ts

case 'CHAT_ARCHITECTURE':
  return process.env.NEXT_PUBLIC_FEATURE_CHAT_ARCHITECTURE === 'true';

Files Summary

Files to Modify

File Change
src/lib/chat.ts Add FormInput, FormInputType, FormResponse, extend FormContent
prisma/schema.prisma Add Feature ↔ ChatMessage relation
src/app/w/[slug]/task/[...taskParams]/artifacts/form.tsx Detect wizard forms, render WizardForm
src/components/features/AITextareaSection.tsx Feature flag, switch to chat-based flow
src/lib/feature-flags.ts Add CHAT_ARCHITECTURE flag
src/app/api/webhook/stakwork/response/route.ts Transform questions to FORM artifacts

New Files to Create

File Purpose
src/components/ui/wizard-form/index.tsx Shared wizard form component
src/app/api/features/[featureId]/architecture/messages/route.ts API for architecture messages
src/services/architecture-conversation.ts Business logic for architecture conversations
src/hooks/useArchitectureMessages.ts Hook for fetching/subscribing to messages

Implementation Order

  1. Types - Extend FormContent in src/lib/chat.ts
  2. Component - Create WizardForm in src/components/ui/wizard-form/
  3. FormArtifact - Extend to detect and render wizard forms
  4. Schema - Add Feature ↔ ChatMessage relation, run migration
  5. Feature Flag - Add CHAT_ARCHITECTURE flag
  6. API/Service - Create architecture conversation endpoints
  7. Webhook - Update Stakwork handler to create FORM artifacts
  8. Integration - Update AITextareaSection with feature flag
  9. Testing - Verify both flows work correctly

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions