Created detailed markdown plans for all items in todo.md: 1. 01-playwright-scaffolding.md - Base Playwright infrastructure 2. 02-magnitude-tests-comprehensive.md - Complete test coverage 3. 03-stream-ai-to-deepgram-tts.md - TTS latency optimization 4. 04-fix-galaxy-node-clicking.md - Galaxy navigation bugs 5. 05-dark-light-mode-theme.md - Dark/light mode with dynamic favicons 6. 06-fix-double-border-desktop.md - UI polish 7. 07-delete-backup-files.md - Code cleanup 8. 08-ai-transition-to-edit.md - Intelligent node creation flow 9. 09-umap-minimum-nodes-analysis.md - Technical analysis Each plan includes: - Detailed problem analysis - Proposed solutions with code examples - Manual Playwright MCP testing strategy - Magnitude test specifications - Implementation steps - Success criteria Ready to implement in sequence. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
291 lines
8.2 KiB
Markdown
291 lines
8.2 KiB
Markdown
# Plan: Allow AI to Transition to Edit Mode in Chat
|
|
|
|
**Priority:** MEDIUM
|
|
**Dependencies:** None
|
|
**Affects:** User experience, conversation flow
|
|
|
|
## Overview
|
|
|
|
Currently, users must manually click "Create Node" to transition from chat to the node editor. We should allow the AI to intelligently suggest and trigger this transition when appropriate during conversation.
|
|
|
|
## Current Flow
|
|
|
|
```
|
|
User: "I want to write about quantum computing"
|
|
AI: "That's interesting! Tell me more..."
|
|
[User continues conversation]
|
|
User: *clicks "Create Node" manually*
|
|
→ Editor opens with AI-generated draft
|
|
```
|
|
|
|
## Proposed Flow
|
|
|
|
```
|
|
User: "I want to write about quantum computing"
|
|
AI: "That's interesting! Tell me more..."
|
|
[Conversation develops]
|
|
AI: "It sounds like you have a solid idea forming. Would you like me to help you draft a node about this?"
|
|
User: "Yes" / Clicks button
|
|
AI: *automatically transitions to edit mode*
|
|
→ Editor opens with AI-generated draft
|
|
```
|
|
|
|
## Implementation Approach
|
|
|
|
### 1. Add Tool Use to AI System Prompt
|
|
|
|
Update the AI system prompt to include a `createNode` tool:
|
|
|
|
#### `app/api/chat/route.ts`
|
|
```typescript
|
|
import { tool } from 'ai';
|
|
import { z } from 'zod';
|
|
|
|
const tools = {
|
|
createNode: tool({
|
|
description: 'Create a thought node when the user has developed a coherent idea worth capturing. Use this when the conversation has explored a topic deeply enough to write about it.',
|
|
parameters: z.object({
|
|
reason: z.string().describe('Why you think this conversation is ready to become a node'),
|
|
}),
|
|
execute: async ({ reason }) => {
|
|
return { shouldTransition: true, reason };
|
|
},
|
|
}),
|
|
};
|
|
|
|
export async function POST(request: Request) {
|
|
const { messages } = await request.json();
|
|
|
|
const result = streamText({
|
|
model: google('gemini-2.0-flash-exp'),
|
|
messages,
|
|
system: `You are a thoughtful AI assistant helping users explore and capture their ideas...
|
|
|
|
When a conversation reaches a natural conclusion or the user has developed a coherent thought, you can suggest creating a node to capture it. Use the createNode tool when:
|
|
- The conversation has explored a specific topic in depth
|
|
- The user has articulated a complete idea or insight
|
|
- There's enough substance for a meaningful blog post
|
|
- The user expresses readiness to capture their thoughts
|
|
|
|
Be conversational and natural when suggesting this - don't force it if the conversation is still developing.`,
|
|
tools,
|
|
maxSteps: 5,
|
|
});
|
|
|
|
return result.toDataStreamResponse();
|
|
}
|
|
```
|
|
|
|
### 2. Handle Tool Calls in Client
|
|
|
|
Update the chat interface to handle the createNode tool call:
|
|
|
|
#### `components/ChatInterface.tsx`
|
|
```typescript
|
|
'use client';
|
|
|
|
import { useChat } from 'ai/react';
|
|
import { useState } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
|
|
export function ChatInterface() {
|
|
const router = useRouter();
|
|
const { messages, input, handleInputChange, handleSubmit } = useChat({
|
|
api: '/api/chat',
|
|
onToolCall: async ({ toolCall }) => {
|
|
if (toolCall.toolName === 'createNode') {
|
|
// Show confirmation UI
|
|
setShowNodeCreationPrompt(true);
|
|
setNodeCreationReason(toolCall.args.reason);
|
|
}
|
|
},
|
|
});
|
|
|
|
const [showNodeCreationPrompt, setShowNodeCreationPrompt] = useState(false);
|
|
const [nodeCreationReason, setNodeCreationReason] = useState('');
|
|
|
|
const handleAcceptNodeCreation = async () => {
|
|
// Generate node draft
|
|
const response = await fetch('/api/generate-node-draft', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
conversation: messages,
|
|
}),
|
|
});
|
|
|
|
const { title, body } = await response.json();
|
|
|
|
// Transition to edit mode
|
|
router.push(`/edit?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`);
|
|
};
|
|
|
|
return (
|
|
<Stack h="100%">
|
|
{/* Chat messages */}
|
|
|
|
{/* Node creation prompt */}
|
|
{showNodeCreationPrompt && (
|
|
<Paper p="md" withBorder>
|
|
<Stack>
|
|
<Text size="sm" c="dimmed">{nodeCreationReason}</Text>
|
|
<Group>
|
|
<Button onClick={handleAcceptNodeCreation}>
|
|
Create Node
|
|
</Button>
|
|
<Button variant="subtle" onClick={() => setShowNodeCreationPrompt(false)}>
|
|
Continue Conversation
|
|
</Button>
|
|
</Group>
|
|
</Stack>
|
|
</Paper>
|
|
)}
|
|
</Stack>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 3. Alternative: Button-Based Approach (Simpler)
|
|
|
|
Instead of using tool calls, simply add a button that appears contextually:
|
|
|
|
```typescript
|
|
export function ChatInterface() {
|
|
const { messages } = useChat();
|
|
const [showCreateButton, setShowCreateButton] = useState(false);
|
|
|
|
// Show "Create Node" button after 5+ messages
|
|
useEffect(() => {
|
|
if (messages.length >= 5) {
|
|
setShowCreateButton(true);
|
|
}
|
|
}, [messages.length]);
|
|
|
|
return (
|
|
<Stack>
|
|
{/* Messages */}
|
|
|
|
{showCreateButton && (
|
|
<Paper p="md" withBorder bg="gray.0">
|
|
<Group justify="space-between">
|
|
<Stack gap="xs">
|
|
<Text fw={500}>Ready to capture this idea?</Text>
|
|
<Text size="sm" c="dimmed">
|
|
You've explored this topic well. Would you like to create a node?
|
|
</Text>
|
|
</Stack>
|
|
<Button onClick={handleCreateNode}>
|
|
Create Node
|
|
</Button>
|
|
</Group>
|
|
</Paper>
|
|
)}
|
|
</Stack>
|
|
);
|
|
}
|
|
```
|
|
|
|
## Testing Strategy
|
|
|
|
### Manual Playwright MCP Test
|
|
|
|
```typescript
|
|
test('AI suggests creating node after deep conversation', async ({ page }) => {
|
|
await page.goto('/chat');
|
|
|
|
// Have a conversation
|
|
await sendMessage(page, 'I want to write about philosophy');
|
|
await waitForAIResponse(page);
|
|
|
|
await sendMessage(page, 'Specifically about existentialism');
|
|
await waitForAIResponse(page);
|
|
|
|
await sendMessage(page, 'And how it relates to modern life');
|
|
await waitForAIResponse(page);
|
|
|
|
// Check if AI suggests creating node
|
|
await expect(page.getByText(/create a node/i)).toBeVisible({ timeout: 30000 });
|
|
|
|
// Click accept
|
|
await page.click('button:has-text("Create Node")');
|
|
|
|
// Should navigate to editor
|
|
await expect(page).toHaveURL(/\/edit/);
|
|
await expect(page.getByRole('textbox', { name: /title/i })).toBeVisible();
|
|
});
|
|
```
|
|
|
|
### Magnitude Test
|
|
|
|
```typescript
|
|
import { test } from 'magnitude-test';
|
|
|
|
test('AI intelligently suggests creating node', async (agent) => {
|
|
await agent.open('http://localhost:3000/chat');
|
|
|
|
await agent.act('Have a conversation about quantum computing');
|
|
await agent.act('Discuss multiple aspects over 5+ messages');
|
|
|
|
await agent.check('AI suggests creating a node');
|
|
await agent.check('Suggestion includes reasoning');
|
|
|
|
await agent.act('Click "Create Node" button');
|
|
await agent.check('Transitions to edit mode');
|
|
await agent.check('Editor has AI-generated draft');
|
|
});
|
|
|
|
test('User can decline node creation and continue chatting', async (agent) => {
|
|
await agent.open('http://localhost:3000/chat');
|
|
|
|
await agent.act('Have a conversation that triggers node suggestion');
|
|
await agent.check('AI suggests creating a node');
|
|
|
|
await agent.act('Click "Continue Conversation"');
|
|
await agent.check('Suggestion dismisses');
|
|
await agent.check('Can continue chatting');
|
|
});
|
|
```
|
|
|
|
## Implementation Steps
|
|
|
|
1. **Choose approach**
|
|
- Tool-based (more intelligent, AI decides)
|
|
- Button-based (simpler, always available after N messages)
|
|
- Hybrid (both)
|
|
|
|
2. **Implement AI tool/prompt**
|
|
- Add createNode tool definition
|
|
- Update system prompt
|
|
- Handle tool calls
|
|
|
|
3. **Update ChatInterface**
|
|
- Add suggestion UI
|
|
- Handle accept/decline
|
|
- Transition to edit mode
|
|
|
|
4. **Test with Playwright MCP**
|
|
- Test suggestion appears
|
|
- Test accept flow
|
|
- Test decline flow
|
|
|
|
5. **Add Magnitude tests**
|
|
|
|
6. **Commit and push**
|
|
|
|
## Success Criteria
|
|
|
|
- ✅ AI suggests node creation at appropriate times
|
|
- ✅ User can accept and transition to edit mode
|
|
- ✅ User can decline and continue conversation
|
|
- ✅ Transition is smooth and intuitive
|
|
- ✅ Works well in conversation flow
|
|
- ✅ Playwright MCP tests pass
|
|
- ✅ Magnitude tests pass
|
|
|
|
## Files to Update
|
|
|
|
1. `app/api/chat/route.ts` - Add tool or enhanced prompt
|
|
2. `components/ChatInterface.tsx` - Add suggestion UI and handling
|
|
3. `tests/playwright/ai-to-edit.spec.ts` - Manual tests
|
|
4. `tests/magnitude/ai-to-edit.mag.ts` - Magnitude tests
|