- Remove unused setIsGoosehintsModalOpen parameter in AppLayout - Add eslint-disable comments for insights and error in SessionsInsights - Remove unused TabsList and TabsTrigger imports in SettingsView
16 KiB
Chat + Document Integration
Overview
The collaborative document editor now integrates with the chat system, allowing users to:
- Ask Goose about their document via chat
- See Goose respond by editing the document directly
- Have a natural conversation while Goose collaborates in real-time
User Flow
┌─────────────────────────────────────────────────────────────────┐
│ Goose Desktop │
├──────────────────────┬──────────────────────────────────────────┤
│ │ │
│ Chat Panel │ Document Editor │
│ │ │
│ User: "Make this │ "The quick brown fox..." │
│ more exciting" │ │
│ │ 🤖 Goose enabled │
│ Goose: "I'll make │ │
│ it more dynamic!" │ 🤖 Goose is editing... │
│ │ │
│ *Goose edits doc* │ "The lightning-fast brown fox │
│ │ leaps gracefully..." │
│ │ │
│ Goose: "Done! I've │ ✅ Edit complete │
│ made it more │ │
│ exciting." │ │
│ │ │
└──────────────────────┴──────────────────────────────────────────┘
How It Works
1. User Clicks "Ask Goose"
When the user clicks the "Ask Goose" button in the document editor:
// In CollaborativeDocEditor.tsx
const handleAskGoose = () => {
const content = editor.getHTML();
const plainText = editor.getText();
const selectedText = editor.state.doc.textBetween(from, to);
// Create context message
const contextMessage = selectedText
? `I'm working on a document and need help with this section:\n\n"${selectedText}"\n\n...`
: `I'm working on a document and need help. Here's what I have so far:\n\n${plainText}...`;
// Populate chat input
window.dispatchEvent(new CustomEvent('populate-chat-input', {
detail: {
message: contextMessage,
docId,
metadata: {
type: 'document-assist',
docId,
content,
selectedText,
selection: { from, to },
}
}
}));
};
2. Chat Input Gets Populated
The chat component listens for this event and populates the input:
// In ChatInput.tsx or similar
useEffect(() => {
const handlePopulateInput = (e: CustomEvent) => {
const { message, docId, metadata } = e.detail;
// Set the input value
setInputValue(message);
// Store metadata for context
setDocumentContext({
docId,
...metadata
});
// Optionally auto-focus the input
inputRef.current?.focus();
};
window.addEventListener('populate-chat-input', handlePopulateInput);
return () => window.removeEventListener('populate-chat-input', handlePopulateInput);
}, []);
3. User Sends Message
User can:
- Edit the pre-filled message
- Add more context
- Send as-is
4. Goose Receives Context
When Goose receives the message, it has access to:
- The document ID
- Full document content
- Selected text (if any)
- Selection range
# In Goose backend
def handle_message(message, metadata):
if metadata.get('type') == 'document-assist':
doc_id = metadata['docId']
content = metadata['content']
selected_text = metadata['selectedText']
# Goose can now:
# 1. Analyze the document
# 2. Generate improvements
# 3. Edit the document directly
# Example: Improve selected text
improved = improve_text(selected_text)
edit_document(doc_id, 'replace',
from_pos=metadata['selection']['from'],
to_pos=metadata['selection']['to'],
text=improved)
5. Goose Edits Document
Goose uses the document API to make edits:
// Goose executes this
const editor = window.gooseEditors[docId];
editor.replaceText(from, to, improvedText);
User sees:
- Green "Goose is editing..." indicator
- Text changing in real-time
- Goose's response in chat
Integration Points
Event: populate-chat-input
Dispatched by: Document editor
Listened by: Chat input component
Payload:
{
message: string, // Pre-filled message
docId: string, // Document ID
metadata: {
type: 'document-assist',
docId: string,
content: string, // Full HTML content
selectedText: string, // Selected text (if any)
selection: {
from: number,
to: number
}
}
}
Event: goose-doc-assist
Dispatched by: Document editor
Listened by: Goose backend (optional)
Payload:
{
docId: string,
content: string,
selectedText: string,
selection: { from: number, to: number },
action: 'assist'
}
Implementation Steps
Step 1: Update Chat Input Component
// In ChatInput.tsx or RichChatInput.tsx
const [documentContext, setDocumentContext] = useState<any>(null);
useEffect(() => {
const handlePopulateInput = (e: CustomEvent) => {
const { message, docId, metadata } = e.detail;
// Set input value
setInputValue(message);
// Store context
setDocumentContext({
docId,
...metadata
});
// Focus input
inputRef.current?.focus();
};
window.addEventListener('populate-chat-input', handlePopulateInput as EventListener);
return () => window.removeEventListener('populate-chat-input', handlePopulateInput as EventListener);
}, []);
// When sending message, include document context
const handleSend = () => {
sendMessage(inputValue, {
documentContext: documentContext || undefined
});
// Clear context after sending
setDocumentContext(null);
};
Step 2: Update Message Handler
// In message handling logic
const sendMessage = async (text: string, metadata?: any) => {
const message = {
role: 'user',
content: text,
metadata: metadata || {}
};
// Send to Goose
const response = await gooseAPI.sendMessage(message);
// If response includes document edits, they'll happen automatically
// via the window.gooseEditors API
};
Step 3: Goose Backend Integration
# In Goose message handler
async def handle_message(message: str, metadata: dict):
# Check if this is a document-related message
if metadata.get('documentContext'):
doc_context = metadata['documentContext']
doc_id = doc_context['docId']
# Process the request
if doc_context.get('selectedText'):
# User selected text and wants help
result = await improve_text(doc_context['selectedText'])
# Edit the document
await edit_document(
doc_id=doc_id,
action='replace',
from_pos=doc_context['selection']['from'],
to_pos=doc_context['selection']['to'],
text=result
)
return f"I've improved the selected text. Check the document!"
else:
# User wants general help with the document
result = await analyze_document(doc_context['content'])
return result
# Regular message handling
return await process_message(message)
Example Conversations
Example 1: Improve Selection
User: *selects "The quick brown fox"*
User: *clicks "Ask Goose"*
Chat Input: "I'm working on a document and need help with this section:
"The quick brown fox"
Full document context:
The quick brown fox jumps over the lazy dog..."
User: "Make this more exciting"
User: *sends*
Goose: "I'll make it more dynamic!"
Goose: *edits document*
→ "The lightning-fast brown fox"
Goose: "Done! I've made it more exciting by adding 'lightning-fast' to emphasize speed."
Example 2: Add Content
User: *clicks "Ask Goose" (no selection)*
Chat Input: "I'm working on a document and need help. Here's what I have so far:
Introduction
The quick brown fox jumps over the lazy dog..."
User: "Add a conclusion paragraph"
User: *sends*
Goose: "I'll add a conclusion for you!"
Goose: *edits document*
→ Appends: "\n\nConclusion\n\nIn summary, the agility and speed of the fox demonstrate..."
Goose: "I've added a conclusion paragraph that summarizes the main points."
Example 3: Format Document
User: "Can you format this document with proper headings?"
Goose: "I'll organize it with headings!"
Goose: *edits document*
→ Converts first line to H1
→ Adds H2 for sections
→ Creates bullet lists
Goose: "I've formatted your document with:
- H1 for the title
- H2 for main sections
- Bullet lists for key points"
Example 4: Fix Grammar
User: *selects text with errors*
User: "Fix the grammar"
Goose: "I'll fix the grammar issues!"
Goose: *edits document*
→ Fixes typos
→ Corrects grammar
→ Improves punctuation
Goose: "Fixed! I corrected:
- 'benifits' → 'benefits'
- 'is' → 'are'
- Added missing commas"
Visual Indicators
In Document Editor
Before Goose edits:
┌────────────────────────────────────┐
│ Collaborative Document │
│ ID: doc-123 🤖 Goose enabled │
├────────────────────────────────────┤
│ [Toolbar] │
├────────────────────────────────────┤
│ The quick brown fox... │
└────────────────────────────────────┘
During Goose edits:
┌────────────────────────────────────┐
│ Collaborative Document │
│ ID: doc-123 🤖 Goose is editing...│ ⚡
├────────────────────────────────────┤
│ [Toolbar] │
├────────────────────────────────────┤
│ The lightning-fast brown fox... │
└────────────────────────────────────┘
In Chat Panel
User message:
┌────────────────────────────────────┐
│ 👤 You │
│ Make this more exciting │
│ │
│ 📄 Working on: doc-123 │
└────────────────────────────────────┘
Goose response:
┌────────────────────────────────────┐
│ 🤖 Goose │
│ I'll make it more dynamic! │
│ │
│ ✏️ Edited document: doc-123 │
└────────────────────────────────────┘
Advanced Features
1. Multi-Turn Editing
User: "Make this more exciting"
Goose: *edits* "Done!"
User: "Actually, make it more professional"
Goose: *edits again* "Made it more professional!"
User: "Perfect, thanks!"
2. Iterative Refinement
User: "Write an introduction"
Goose: *writes intro*
User: "Make it shorter"
Goose: *shortens intro*
User: "Add a hook"
Goose: *adds hook to intro*
3. Explain Changes
User: "Improve this paragraph"
Goose: *edits*
Goose: "I made these changes:
1. Replaced 'very good' with 'excellent'
2. Added transition words
3. Split long sentence into two
4. Improved flow"
4. Undo Suggestions
User: "Make this more formal"
Goose: *edits*
User: "Actually, I liked it better before"
Goose: "No problem! Press Cmd+Z to undo, or I can revert it for you."
User: *presses Cmd+Z*
Error Handling
Document Not Found
if (!window.gooseEditors[docId]) {
return "I can't find that document. Make sure it's still open.";
}
Goose Disabled
if (!window.gooseEditors[docId].enabled) {
return "Goose collaboration is disabled for this document. Click the toggle button to enable it.";
}
Invalid Selection
if (from > to || from < 0) {
return "The selection range is invalid. Please select text again.";
}
Testing
Manual Test Flow
- Open a document
- Type some text
- Select text
- Click "Ask Goose"
- Verify chat input is populated
- Edit the message
- Send
- Watch Goose edit the document
- Verify changes appear
- Try Cmd+Z to undo
Test Cases
describe('Chat-Document Integration', () => {
it('populates chat input when Ask Goose clicked', () => {
// Click Ask Goose
// Check chat input has document context
});
it('includes document metadata in message', () => {
// Send message
// Verify metadata includes docId, content, selection
});
it('Goose can edit document from chat', () => {
// Simulate Goose response
// Verify document is edited
});
it('shows typing indicator during edit', () => {
// Start edit
// Check for "Goose is editing..." badge
});
it('user can undo Goose edits', () => {
// Goose edits
// Press Cmd+Z
// Verify edit is undone
});
});
Configuration
Enable/Disable Integration
// In CollaborativeDocEditor
const [chatIntegrationEnabled, setChatIntegrationEnabled] = useState(true);
// Only populate chat if enabled
if (chatIntegrationEnabled) {
window.dispatchEvent(new CustomEvent('populate-chat-input', ...));
}
Customize Context Message
const contextMessageTemplate = (selectedText, fullText) => {
if (selectedText) {
return `Help me with: "${selectedText}"`;
}
return `Help me with my document: ${fullText.substring(0, 200)}...`;
};
Summary
The chat-document integration creates a seamless experience where:
- ✅ User can ask Goose about their document via chat
- ✅ Chat input is pre-filled with document context
- ✅ Goose receives full document information
- ✅ Goose can edit the document directly
- ✅ User sees real-time visual feedback
- ✅ Everything is undoable
- ✅ Natural conversation flow
This transforms the document editor from a standalone tool into an integrated AI workspace!
Next Steps:
- Implement
populate-chat-inputlistener in chat component - Add document context to message metadata
- Update Goose backend to handle document edits
- Test the full flow
- Add visual indicators in chat
Status: ✅ Document editor ready, needs chat component integration
Created: November 5, 2025
Branch: spence/doceditor