356 lines
10 KiB
Markdown
356 lines
10 KiB
Markdown
# Final Frontend Implementation Code
|
|
|
|
This document contains all the JavaScript and CSS code to be added to complete the implementation.
|
|
|
|
---
|
|
|
|
## JavaScript Functions to Add to sidebar.js
|
|
|
|
### 1. Writing Mode Empty State Check
|
|
|
|
```javascript
|
|
// Add after state declarations (around line 100)
|
|
const shouldShowWritingEmptyState = () => {
|
|
return agentMode === 'writing' && !currentPlanRef.current;
|
|
};
|
|
```
|
|
|
|
### 2. Summarize Chat History Function
|
|
|
|
```javascript
|
|
// Add with other utility functions
|
|
const summarizeChatHistory = async () => {
|
|
const chatMessages = messages.filter(m => m.role !== 'system');
|
|
|
|
if (chatMessages.length < 4) {
|
|
return { summary: '', useFullHistory: true, cost: 0 };
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(wpAgenticWriter.apiUrl + '/summarize-context', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-WP-Nonce': wpAgenticWriter.nonce,
|
|
},
|
|
body: JSON.stringify({
|
|
chatHistory: chatMessages,
|
|
postId: postId,
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Summarization failed');
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.tokens_saved > 0) {
|
|
console.log(`💡 Context optimized: ~${data.tokens_saved} tokens saved (~$${(data.tokens_saved * 0.0000002).toFixed(4)})`);
|
|
}
|
|
|
|
return {
|
|
summary: data.summary || '',
|
|
useFullHistory: data.use_full_history || false,
|
|
cost: data.cost || 0,
|
|
tokensSaved: data.tokens_saved || 0,
|
|
};
|
|
} catch (error) {
|
|
console.error('Summarization error:', error);
|
|
return { summary: '', useFullHistory: true, cost: 0 };
|
|
}
|
|
};
|
|
```
|
|
|
|
### 3. Detect User Intent Function
|
|
|
|
```javascript
|
|
// Add with other utility functions
|
|
const detectUserIntent = async (lastMessage) => {
|
|
if (!lastMessage || lastMessage.trim().length === 0) {
|
|
return { intent: 'continue_chat', cost: 0 };
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(wpAgenticWriter.apiUrl + '/detect-intent', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-WP-Nonce': wpAgenticWriter.nonce,
|
|
},
|
|
body: JSON.stringify({
|
|
lastMessage: lastMessage,
|
|
hasPlan: Boolean(currentPlanRef.current),
|
|
currentMode: agentMode,
|
|
postId: postId,
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Intent detection failed');
|
|
}
|
|
|
|
const data = await response.json();
|
|
return {
|
|
intent: data.intent || 'continue_chat',
|
|
cost: data.cost || 0,
|
|
};
|
|
} catch (error) {
|
|
console.error('Intent detection error:', error);
|
|
return { intent: 'continue_chat', cost: 0 };
|
|
}
|
|
};
|
|
```
|
|
|
|
### 4. Build Optimized Context Function
|
|
|
|
```javascript
|
|
// Add with other utility functions
|
|
const buildOptimizedContext = async () => {
|
|
const result = await summarizeChatHistory();
|
|
|
|
if (result.useFullHistory) {
|
|
return {
|
|
type: 'full',
|
|
messages: messages.filter(m => m.role !== 'system'),
|
|
cost: 0,
|
|
};
|
|
}
|
|
|
|
return {
|
|
type: 'summary',
|
|
summary: result.summary,
|
|
cost: result.cost,
|
|
tokensSaved: result.tokensSaved,
|
|
};
|
|
};
|
|
```
|
|
|
|
### 5. Handle Reset Command
|
|
|
|
```javascript
|
|
// Add with other command handlers
|
|
const handleResetCommand = async () => {
|
|
if (!confirm('Clear all conversation history? This cannot be undone.')) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Clear frontend state
|
|
setMessages([]);
|
|
currentPlanRef.current = null;
|
|
|
|
// Clear backend chat history
|
|
await fetch(wpAgenticWriter.apiUrl + '/clear-context', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-WP-Nonce': wpAgenticWriter.nonce,
|
|
},
|
|
body: JSON.stringify({ postId: postId }),
|
|
});
|
|
|
|
setMessages([{
|
|
role: 'system',
|
|
type: 'info',
|
|
content: '✅ Context cleared. Starting fresh conversation.'
|
|
}]);
|
|
} catch (error) {
|
|
console.error('Reset error:', error);
|
|
setMessages(prev => [...prev, {
|
|
role: 'system',
|
|
type: 'error',
|
|
content: 'Failed to clear context. Please try again.'
|
|
}]);
|
|
}
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Modifications to Existing Functions
|
|
|
|
### Modify handleSendMessage (detect /reset command)
|
|
|
|
Find the message sending logic and add at the beginning:
|
|
|
|
```javascript
|
|
// Check for reset command
|
|
if (/^\s*(\/reset|\/clear)\s*$/i.test(userMessage)) {
|
|
setInput('');
|
|
await handleResetCommand();
|
|
return;
|
|
}
|
|
|
|
// Check for Writing mode notes warning
|
|
if (agentMode === 'writing' && currentPlanRef.current) {
|
|
setMessages(prev => [...prev,
|
|
{ role: 'user', content: userMessage },
|
|
{
|
|
role: 'system',
|
|
type: 'info',
|
|
content: '💡 Note: Messages in Writing mode are for discussion only. To modify the outline, switch to Planning mode.'
|
|
}
|
|
]);
|
|
}
|
|
```
|
|
|
|
### Modify handleExecuteArticle (add plan check)
|
|
|
|
Add at the very beginning of the function:
|
|
|
|
```javascript
|
|
// Check if plan exists
|
|
if (!currentPlanRef.current) {
|
|
setMessages(prev => [...prev, {
|
|
role: 'system',
|
|
type: 'error',
|
|
content: '⚠️ No outline found. Please create an outline first by switching to Planning mode.'
|
|
}]);
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## UI Components to Add
|
|
|
|
### Render Writing Empty State
|
|
|
|
Add this component function:
|
|
|
|
```javascript
|
|
const renderWritingEmptyState = () => {
|
|
return wp.element.createElement('div', { className: 'wpaw-writing-empty-state' },
|
|
wp.element.createElement('div', { className: 'wpaw-empty-state-content' },
|
|
wp.element.createElement('span', { className: 'wpaw-empty-state-icon' }, '📝'),
|
|
wp.element.createElement('h3', null, 'No Outline Yet'),
|
|
wp.element.createElement('p', null, 'Writing mode requires an outline to structure your article.'),
|
|
wp.element.createElement(Button, {
|
|
isPrimary: true,
|
|
onClick: () => setAgentMode('planning'),
|
|
className: 'wpaw-empty-state-button'
|
|
}, '📝 Create Outline First'),
|
|
wp.element.createElement('p', { className: 'wpaw-empty-state-hint' },
|
|
'Or switch to ',
|
|
wp.element.createElement('button', {
|
|
onClick: () => setAgentMode('chat'),
|
|
className: 'wpaw-link-button'
|
|
}, 'Chat mode'),
|
|
' to discuss your ideas.'
|
|
)
|
|
)
|
|
);
|
|
};
|
|
```
|
|
|
|
### Render Context Indicator
|
|
|
|
Add this component function:
|
|
|
|
```javascript
|
|
const renderContextIndicator = () => {
|
|
const chatMessages = messages.filter(m => m.role !== 'system');
|
|
const messageCount = chatMessages.length;
|
|
const estimatedTokens = messageCount * 500; // Rough estimate
|
|
|
|
if (messageCount === 0) return null;
|
|
|
|
return wp.element.createElement('div', { className: 'wpaw-context-indicator' },
|
|
wp.element.createElement('div', { className: 'wpaw-context-info' },
|
|
wp.element.createElement('span', { className: 'wpaw-context-count' },
|
|
`💬 ${messageCount} messages`
|
|
),
|
|
wp.element.createElement('span', { className: 'wpaw-context-tokens' },
|
|
`~${estimatedTokens} tokens`
|
|
)
|
|
),
|
|
wp.element.createElement('button', {
|
|
className: 'wpaw-context-clear',
|
|
onClick: handleResetCommand,
|
|
title: 'Clear conversation history'
|
|
}, '🗑️ Clear')
|
|
);
|
|
};
|
|
```
|
|
|
|
### Render Contextual Action
|
|
|
|
Add this component function:
|
|
|
|
```javascript
|
|
const renderContextualAction = (intent) => {
|
|
if (!intent || intent === 'continue_chat') return null;
|
|
|
|
const actions = {
|
|
create_outline: {
|
|
icon: '📝',
|
|
title: 'Ready to create an outline?',
|
|
description: 'I can help you structure your article.',
|
|
button: 'Create Outline',
|
|
onClick: () => setAgentMode('planning')
|
|
},
|
|
start_writing: {
|
|
icon: '✍️',
|
|
title: 'Ready to start writing?',
|
|
description: 'Let\'s turn your outline into a full article.',
|
|
button: 'Start Writing',
|
|
onClick: async () => {
|
|
setAgentMode('writing');
|
|
if (currentPlanRef.current) {
|
|
await handleExecuteArticle();
|
|
}
|
|
}
|
|
},
|
|
refine_content: {
|
|
icon: '✨',
|
|
title: 'Want to refine your content?',
|
|
description: 'I can help improve specific sections.',
|
|
button: 'Show Options',
|
|
onClick: () => {} // Could open refinement options
|
|
}
|
|
};
|
|
|
|
const action = actions[intent];
|
|
if (!action) return null;
|
|
|
|
return wp.element.createElement('div', { className: 'wpaw-contextual-action' },
|
|
wp.element.createElement('div', { className: 'wpaw-action-icon' }, action.icon),
|
|
wp.element.createElement('div', { className: 'wpaw-action-content' },
|
|
wp.element.createElement('h4', null, action.title),
|
|
wp.element.createElement('p', null, action.description),
|
|
wp.element.createElement(Button, {
|
|
isPrimary: true,
|
|
onClick: action.onClick
|
|
}, action.button)
|
|
)
|
|
);
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Integration Points
|
|
|
|
### In Main Render (where messages are displayed)
|
|
|
|
Add before the message list:
|
|
|
|
```javascript
|
|
{shouldShowWritingEmptyState() && renderWritingEmptyState()}
|
|
{renderContextIndicator()}
|
|
```
|
|
|
|
### In Message Loop (after assistant messages)
|
|
|
|
Add intent detection display:
|
|
|
|
```javascript
|
|
{message.detectedIntent && renderContextualAction(message.detectedIntent)}
|
|
```
|
|
|
|
---
|
|
|
|
This completes all the JavaScript logic needed for the frontend implementation.
|