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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions