# Voice Agent Creation Fix — Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Fix voice agent creation so clicking "Create Agent" in the dashboard wizard successfully creates an ElevenLabs agent.

**Architecture:** Two isolated bugs — a greetingMessage schema mismatch (wizard sends string, validator expects object) and a tools-registration rollback (failed tools delete a successfully created agent). Fix both independently.

**Tech Stack:** Next.js 14 App Router, React, TypeScript, Zod, ElevenLabs API

**Working directory:** `mawidi-site/` inside the `voiceagent` worktree at `/Users/Asim/Desktop/mawidi_codex/mawidi-site/.claude/worktrees/voiceagent/mawidi-site`

---

### Task 1: Fix greetingMessage in VoiceAgentSetupWizard.tsx

**Files:**
- Modify: `app/[lang]/dashboard/components/voice-agent/VoiceAgentSetupWizard.tsx`

The bug: line 98 declares `greetingMessage: string`, line 129 sends it as a plain string. The API validator (`provisionAgentSchema`) expects `{ ar?: string, en?: string }`. Zod rejects the string → 400.

**Step 1: Replace the single greetingMessage state with two bilingual states**

On line 98, replace:
```tsx
const [greetingMessage, setGreetingMessage] = useState("");
```
With:
```tsx
const [greetingEn, setGreetingEn] = useState("");
const [greetingAr, setGreetingAr] = useState("");
```

**Step 2: Fix the API call body (line 129)**

Replace:
```tsx
greetingMessage: greetingMessage || undefined,
```
With:
```tsx
greetingMessage:
  greetingEn || greetingAr
    ? {
        en: greetingEn.trim() || undefined,
        ar: greetingAr.trim() || undefined,
      }
    : undefined,
```

**Step 3: Update the Step 2 greeting UI (lines 329–347)**

Replace the single textarea block:
```tsx
{/* Greeting Message */}
<div>
  <label className="block text-sm font-medium text-slate-700 mb-2">
    {isAr
      ? "رسالة الترحيب (اختياري)"
      : "Greeting Message (Optional)"}
  </label>
  <textarea
    value={greetingMessage}
    onChange={(e) => setGreetingMessage(e.target.value)}
    placeholder={
      isAr
        ? "مرحباً! كيف يمكنني مساعدتك اليوم؟"
        : "Hello! How can I help you today?"
    }
    rows={3}
    className="w-full rounded-xl border border-slate-200 px-4 py-3 text-sm focus:border-brand-green focus:ring-1 focus:ring-brand-green outline-none resize-none"
  />
</div>
```
With two textareas:
```tsx
{/* Greeting Message */}
<div>
  <label className="block text-sm font-medium text-slate-700 mb-2">
    {isAr
      ? "رسالة الترحيب (اختياري)"
      : "Greeting Message (Optional)"}
  </label>
  <div className="space-y-2">
    <textarea
      value={greetingEn}
      onChange={(e) => setGreetingEn(e.target.value)}
      placeholder="Hello! How can I help you today?"
      rows={2}
      className="w-full rounded-xl border border-slate-200 px-4 py-3 text-sm focus:border-brand-green focus:ring-1 focus:ring-brand-green outline-none resize-none"
    />
    <textarea
      value={greetingAr}
      onChange={(e) => setGreetingAr(e.target.value)}
      placeholder="مرحباً! كيف يمكنني مساعدتك اليوم؟"
      rows={2}
      dir="rtl"
      className="w-full rounded-xl border border-slate-200 px-4 py-3 text-sm focus:border-brand-green focus:ring-1 focus:ring-brand-green outline-none resize-none"
    />
  </div>
</div>
```

**Step 4: Update the Step 5 review section (lines 776–784)**

Replace:
```tsx
{greetingMessage && (
  <div className="p-4 rounded-xl bg-slate-50">
    <span className="text-sm text-slate-500 block mb-1">
      {isAr ? "رسالة الترحيب" : "Greeting"}
    </span>
    <span className="text-sm text-slate-800">
      {greetingMessage}
    </span>
  </div>
)}
```
With:
```tsx
{(greetingEn || greetingAr) && (
  <div className="p-4 rounded-xl bg-slate-50">
    <span className="text-sm text-slate-500 block mb-1">
      {isAr ? "رسالة الترحيب" : "Greeting"}
    </span>
    {greetingEn && (
      <span className="text-sm text-slate-800 block">EN: {greetingEn}</span>
    )}
    {greetingAr && (
      <span className="text-sm text-slate-800 block" dir="rtl">
        AR: {greetingAr}
      </span>
    )}
  </div>
)}
```

**Step 5: Handle toolsWarning in the success handler (lines 148–158 in handleCreate)**

Replace:
```tsx
      onComplete();
    } catch (err: unknown) {
```
With:
```tsx
      const data = await res.json().catch(() => null);
      if (data?.data?.toolsWarning) {
        // Agent created, but booking webhook tools failed — non-fatal
        console.warn("Voice agent created without booking tools:", data.data.toolsWarning);
      }
      onComplete();
    } catch (err: unknown) {
```

Wait — the current code does `onComplete()` before `catch`, but doesn't parse the response body on success. Replace the success block precisely:

Current lines 148–158:
```tsx
      if (!res.ok) {
        const data = await res.json().catch(() => null);
        if (data?.errorType) setErrorType(data.errorType);
        throw new Error(
          data?.message ||
            data?.error ||
            (isAr ? "فشل في إنشاء الوكيل" : "Failed to create agent"),
        );
      }

      onComplete();
```
Replace with:
```tsx
      if (!res.ok) {
        const data = await res.json().catch(() => null);
        if (data?.errorType) setErrorType(data.errorType);
        throw new Error(
          data?.message ||
            data?.error ||
            (isAr ? "فشل في إنشاء الوكيل" : "Failed to create agent"),
        );
      }

      const successData = await res.json().catch(() => null);
      if (successData?.data?.toolsWarning) {
        // Non-fatal: agent created but booking webhook tools pending
        console.warn("Agent created without booking tools (will retry)");
      }
      onComplete();
```

**Step 6: Type-check the file**

```bash
cd /Users/Asim/Desktop/mawidi_codex/mawidi-site/.claude/worktrees/voiceagent/mawidi-site
npx tsc --noEmit 2>&1 | grep -E "voice-agent/VoiceAgentSetupWizard|error TS" | head -20
```
Expected: no errors for this file.

**Step 7: Lint**

```bash
npx eslint app/\[lang\]/dashboard/components/voice-agent/VoiceAgentSetupWizard.tsx --max-warnings 0
```
Expected: no errors.

**Step 8: Commit**

```bash
git add app/\[lang\]/dashboard/components/voice-agent/VoiceAgentSetupWizard.tsx
git commit -m "fix(voice-agent): send greetingMessage as bilingual object to match API schema

Wizard was sending greetingMessage as a plain string; provisionAgentSchema
expects { ar?, en? }. Replace single textarea with English + Arabic inputs.
Also handle toolsWarning in success response.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
```

---

### Task 2: Remove destructive tools-registration rollback from provision route

**Files:**
- Modify: `app/api/voice-agent/provision/route.ts`

The bug: lines 133–158 — when `registerTools()` fails, the route calls `deleteAgent()` to destroy the newly created agent, then returns 500. The agent is gone and the user must retry. Instead, save the agent and flag the issue as a warning.

**Step 1: Replace the fatal tools-failure block (lines 133–158)**

Current code:
```ts
      if (!toolsResult.success) {
        logger.error(
          "Failed to register server tools after provisioning",
          new Error(toolsResult.error || "Unknown tools registration error"),
          {
            userId: user.id,
            agentId: agent.agent_id,
          },
        );
        await elevenLabsService
          .deleteAgent(agent.agent_id)
          .catch((cleanupError) =>
            logger.error(
              "Failed to cleanup newly provisioned agent after tools registration failure",
              cleanupError,
              { userId: user.id, agentId: agent.agent_id },
            ),
          );
        return NextResponse.json(
          {
            error: "Service error",
            message:
              "Voice agent was created but tools setup failed. Please retry provisioning.",
          },
          { status: 500 },
        );
      }
```

Replace with:
```ts
      const toolsConfigured = toolsResult.success;
      if (!toolsResult.success) {
        logger.error(
          "Failed to register server tools after provisioning — agent saved without tools",
          new Error(toolsResult.error || "Unknown tools registration error"),
          {
            userId: user.id,
            agentId: agent.agent_id,
          },
        );
      }
```

**Step 2: Update the 201 response to include toolsWarning (lines 274–304)**

Find:
```ts
            toolsEnabled: true,
```
Replace with:
```ts
            toolsEnabled: toolsConfigured,
            toolsWarning: toolsConfigured
              ? undefined
              : "Booking tools could not be registered and will need to be configured.",
```

**Step 3: Type-check**

```bash
npx tsc --noEmit 2>&1 | grep -E "provision/route|error TS" | head -20
```
Expected: no errors.

**Step 4: Lint**

```bash
npx eslint app/api/voice-agent/provision/route.ts --max-warnings 0
```
Expected: no errors.

**Step 5: Commit**

```bash
git add app/api/voice-agent/provision/route.ts
git commit -m "fix(voice-agent): don't delete agent when tools registration fails

Tools registration failure used to destroy the newly created ElevenLabs
agent and return 500. Now saves the agent to DB regardless, returns 201
with toolsWarning flag. Booking tools can be re-applied separately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
```

---

### Task 3: Full verification

**Step 1: Run full typecheck**

```bash
cd /Users/Asim/Desktop/mawidi_codex/mawidi-site/.claude/worktrees/voiceagent/mawidi-site
npx tsc --noEmit 2>&1 | tail -5
```
Expected: `Found 0 errors.`

**Step 2: Run lint on both changed files**

```bash
npx eslint \
  "app/[lang]/dashboard/components/voice-agent/VoiceAgentSetupWizard.tsx" \
  "app/api/voice-agent/provision/route.ts" \
  --max-warnings 0
```
Expected: no output (clean).

**Step 3: Verify ElevenLabs agents via MCP**

Use the `list_agents` ElevenLabs MCP tool to confirm existing agents are present (sanity check the API key works).

**Step 4: Browser end-to-end test (if logged in)**

1. Navigate to `http://localhost:9000/en/dashboard?tab=voice-agent`
2. Step through the 5-step wizard
3. On Step 2, fill in both English and Arabic greeting fields
4. Click "Create Agent" on Step 5
5. Expected: dashboard loads with the new agent, no error shown

**Step 5: Confirm agent created via MCP**

Call `list_agents` ElevenLabs MCP tool — the new agent should appear at the top.

**Step 6: Final commit if any last fixes needed**

```bash
git log --oneline -5
```
Confirm two fix commits are present on the `voiceagent` branch.
