mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-19 18:35:18 +02:00
Merge branch 'dev' of github.com:rowboatlabs/rowboat into dev
This commit is contained in:
commit
68117ac8d2
7 changed files with 355 additions and 1 deletions
|
|
@ -38,6 +38,7 @@ import { Shimmer } from '@/components/ai-elements/shimmer';
|
||||||
import { Tool, ToolContent, ToolHeader, ToolInput, ToolOutput } from '@/components/ai-elements/tool';
|
import { Tool, ToolContent, ToolHeader, ToolInput, ToolOutput } from '@/components/ai-elements/tool';
|
||||||
import { PermissionRequest } from '@/components/ai-elements/permission-request';
|
import { PermissionRequest } from '@/components/ai-elements/permission-request';
|
||||||
import { AskHumanRequest } from '@/components/ai-elements/ask-human-request';
|
import { AskHumanRequest } from '@/components/ai-elements/ask-human-request';
|
||||||
|
import { Suggestions } from '@/components/ai-elements/suggestions';
|
||||||
import { ToolPermissionRequestEvent, AskHumanRequestEvent } from '@x/shared/src/runs.js';
|
import { ToolPermissionRequestEvent, AskHumanRequestEvent } from '@x/shared/src/runs.js';
|
||||||
import {
|
import {
|
||||||
SidebarInset,
|
SidebarInset,
|
||||||
|
|
@ -278,16 +279,28 @@ const collectFilePaths = (nodes: TreeNode[]): string[] =>
|
||||||
interface ChatInputInnerProps {
|
interface ChatInputInnerProps {
|
||||||
onSubmit: (message: PromptInputMessage, mentions?: FileMention[]) => void
|
onSubmit: (message: PromptInputMessage, mentions?: FileMention[]) => void
|
||||||
isProcessing: boolean
|
isProcessing: boolean
|
||||||
|
presetMessage?: string
|
||||||
|
onPresetMessageConsumed?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function ChatInputInner({
|
function ChatInputInner({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
isProcessing,
|
isProcessing,
|
||||||
|
presetMessage,
|
||||||
|
onPresetMessageConsumed,
|
||||||
}: ChatInputInnerProps) {
|
}: ChatInputInnerProps) {
|
||||||
const controller = usePromptInputController()
|
const controller = usePromptInputController()
|
||||||
const message = controller.textInput.value
|
const message = controller.textInput.value
|
||||||
const canSubmit = Boolean(message.trim()) && !isProcessing
|
const canSubmit = Boolean(message.trim()) && !isProcessing
|
||||||
|
|
||||||
|
// Handle preset message from suggestions
|
||||||
|
useEffect(() => {
|
||||||
|
if (presetMessage) {
|
||||||
|
controller.textInput.setInput(presetMessage)
|
||||||
|
onPresetMessageConsumed?.()
|
||||||
|
}
|
||||||
|
}, [presetMessage, controller.textInput, onPresetMessageConsumed])
|
||||||
|
|
||||||
const handleSubmit = useCallback(() => {
|
const handleSubmit = useCallback(() => {
|
||||||
if (!canSubmit) return
|
if (!canSubmit) return
|
||||||
onSubmit({ text: message.trim(), files: [] }, controller.mentions.mentions)
|
onSubmit({ text: message.trim(), files: [] }, controller.mentions.mentions)
|
||||||
|
|
@ -334,6 +347,8 @@ interface ChatInputWithMentionsProps {
|
||||||
visibleFiles: string[]
|
visibleFiles: string[]
|
||||||
onSubmit: (message: PromptInputMessage, mentions?: FileMention[]) => void
|
onSubmit: (message: PromptInputMessage, mentions?: FileMention[]) => void
|
||||||
isProcessing: boolean
|
isProcessing: boolean
|
||||||
|
presetMessage?: string
|
||||||
|
onPresetMessageConsumed?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function ChatInputWithMentions({
|
function ChatInputWithMentions({
|
||||||
|
|
@ -342,12 +357,16 @@ function ChatInputWithMentions({
|
||||||
visibleFiles,
|
visibleFiles,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
isProcessing,
|
isProcessing,
|
||||||
|
presetMessage,
|
||||||
|
onPresetMessageConsumed,
|
||||||
}: ChatInputWithMentionsProps) {
|
}: ChatInputWithMentionsProps) {
|
||||||
return (
|
return (
|
||||||
<PromptInputProvider knowledgeFiles={knowledgeFiles} recentFiles={recentFiles} visibleFiles={visibleFiles}>
|
<PromptInputProvider knowledgeFiles={knowledgeFiles} recentFiles={recentFiles} visibleFiles={visibleFiles}>
|
||||||
<ChatInputInner
|
<ChatInputInner
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
isProcessing={isProcessing}
|
isProcessing={isProcessing}
|
||||||
|
presetMessage={presetMessage}
|
||||||
|
onPresetMessageConsumed={onPresetMessageConsumed}
|
||||||
/>
|
/>
|
||||||
</PromptInputProvider>
|
</PromptInputProvider>
|
||||||
)
|
)
|
||||||
|
|
@ -386,6 +405,7 @@ function App() {
|
||||||
const [runId, setRunId] = useState<string | null>(null)
|
const [runId, setRunId] = useState<string | null>(null)
|
||||||
const [isProcessing, setIsProcessing] = useState(false)
|
const [isProcessing, setIsProcessing] = useState(false)
|
||||||
const [agentId] = useState<string>('copilot')
|
const [agentId] = useState<string>('copilot')
|
||||||
|
const [presetMessage, setPresetMessage] = useState<string | undefined>(undefined)
|
||||||
|
|
||||||
// Runs history state
|
// Runs history state
|
||||||
type RunListItem = { id: string; title?: string; createdAt: string; agentId: string }
|
type RunListItem = { id: string; title?: string; createdAt: string; agentId: string }
|
||||||
|
|
@ -1656,12 +1676,17 @@ function App() {
|
||||||
<div className="sticky bottom-0 z-10 bg-background pb-12 pt-0 shadow-lg">
|
<div className="sticky bottom-0 z-10 bg-background pb-12 pt-0 shadow-lg">
|
||||||
<div className="pointer-events-none absolute inset-x-0 -top-6 h-6 bg-linear-to-t from-background to-transparent" />
|
<div className="pointer-events-none absolute inset-x-0 -top-6 h-6 bg-linear-to-t from-background to-transparent" />
|
||||||
<div className="mx-auto w-full max-w-4xl px-4">
|
<div className="mx-auto w-full max-w-4xl px-4">
|
||||||
|
{!hasConversation && (
|
||||||
|
<Suggestions onSelect={setPresetMessage} className="mb-3 justify-center" />
|
||||||
|
)}
|
||||||
<ChatInputWithMentions
|
<ChatInputWithMentions
|
||||||
knowledgeFiles={knowledgeFiles}
|
knowledgeFiles={knowledgeFiles}
|
||||||
recentFiles={recentWikiFiles}
|
recentFiles={recentWikiFiles}
|
||||||
visibleFiles={visibleKnowledgeFiles}
|
visibleFiles={visibleKnowledgeFiles}
|
||||||
onSubmit={handlePromptSubmit}
|
onSubmit={handlePromptSubmit}
|
||||||
isProcessing={isProcessing}
|
isProcessing={isProcessing}
|
||||||
|
presetMessage={presetMessage}
|
||||||
|
onPresetMessageConsumed={() => setPresetMessage(undefined)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
import { Mail, Calendar, FolderOpen, FileText } from 'lucide-react'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
export interface Suggestion {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
prompt: string
|
||||||
|
icon: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultSuggestions: Suggestion[] = [
|
||||||
|
{
|
||||||
|
id: 'email-draft',
|
||||||
|
label: 'Draft an email',
|
||||||
|
prompt: "Let's draft an email response to [name]",
|
||||||
|
icon: <Mail className="h-4 w-4" />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'meeting-prep',
|
||||||
|
label: 'Prep for a meeting',
|
||||||
|
prompt: 'Help me prep for my next meeting with [name]',
|
||||||
|
icon: <Calendar className="h-4 w-4" />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'doc-collab',
|
||||||
|
label: 'Work on a document',
|
||||||
|
prompt: "Let's work on [document name]",
|
||||||
|
icon: <FileText className="h-4 w-4" />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'organize-files',
|
||||||
|
label: 'Organize files',
|
||||||
|
prompt: 'Help me organize [folder or files]',
|
||||||
|
icon: <FolderOpen className="h-4 w-4" />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
interface SuggestionsProps {
|
||||||
|
suggestions?: Suggestion[]
|
||||||
|
onSelect: (prompt: string) => void
|
||||||
|
className?: string
|
||||||
|
vertical?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Suggestions({
|
||||||
|
suggestions = defaultSuggestions,
|
||||||
|
onSelect,
|
||||||
|
className,
|
||||||
|
vertical = false,
|
||||||
|
}: SuggestionsProps) {
|
||||||
|
return (
|
||||||
|
<div className={cn(
|
||||||
|
'flex gap-2',
|
||||||
|
vertical ? 'flex-col items-start' : 'flex-wrap justify-center',
|
||||||
|
className
|
||||||
|
)}>
|
||||||
|
{suggestions.map((suggestion) => (
|
||||||
|
<button
|
||||||
|
key={suggestion.id}
|
||||||
|
onClick={() => onSelect(suggestion.prompt)}
|
||||||
|
className={cn(
|
||||||
|
'inline-flex items-center gap-2 px-3 py-1.5 rounded-full',
|
||||||
|
'text-sm text-muted-foreground',
|
||||||
|
'border border-border bg-background',
|
||||||
|
'hover:bg-muted hover:text-foreground hover:border-muted-foreground/30',
|
||||||
|
'transition-colors duration-150',
|
||||||
|
'focus:outline-none focus-visible:ring-2 focus-visible:ring-ring'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{suggestion.icon}
|
||||||
|
<span>{suggestion.label}</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,7 @@ import { Shimmer } from '@/components/ai-elements/shimmer'
|
||||||
import { Tool, ToolContent, ToolHeader, ToolInput, ToolOutput } from '@/components/ai-elements/tool'
|
import { Tool, ToolContent, ToolHeader, ToolInput, ToolOutput } from '@/components/ai-elements/tool'
|
||||||
import { PermissionRequest } from '@/components/ai-elements/permission-request'
|
import { PermissionRequest } from '@/components/ai-elements/permission-request'
|
||||||
import { AskHumanRequest } from '@/components/ai-elements/ask-human-request'
|
import { AskHumanRequest } from '@/components/ai-elements/ask-human-request'
|
||||||
|
import { Suggestions } from '@/components/ai-elements/suggestions'
|
||||||
import { type PromptInputMessage, type FileMention } from '@/components/ai-elements/prompt-input'
|
import { type PromptInputMessage, type FileMention } from '@/components/ai-elements/prompt-input'
|
||||||
import { useMentionDetection } from '@/hooks/use-mention-detection'
|
import { useMentionDetection } from '@/hooks/use-mention-detection'
|
||||||
import { MentionPopover } from '@/components/mention-popover'
|
import { MentionPopover } from '@/components/mention-popover'
|
||||||
|
|
@ -544,6 +545,16 @@ export function ChatSidebar({
|
||||||
|
|
||||||
{/* Input area - responsive to sidebar width, matches floating bar position exactly */}
|
{/* Input area - responsive to sidebar width, matches floating bar position exactly */}
|
||||||
<div className="absolute bottom-6 left-14 right-6 z-10" ref={containerRef}>
|
<div className="absolute bottom-6 left-14 right-6 z-10" ref={containerRef}>
|
||||||
|
{!hasConversation && (
|
||||||
|
<Suggestions
|
||||||
|
onSelect={(prompt) => {
|
||||||
|
onMessageChange(prompt)
|
||||||
|
setTimeout(() => textareaRef.current?.focus(), 0)
|
||||||
|
}}
|
||||||
|
vertical
|
||||||
|
className="mb-3"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div className="flex items-center gap-2 bg-background border border-border rounded-3xl shadow-xl px-4 py-2.5">
|
<div className="flex items-center gap-2 bg-background border border-border rounded-3xl shadow-xl px-4 py-2.5">
|
||||||
<div className="relative flex-1 min-w-0">
|
<div className="relative flex-1 min-w-0">
|
||||||
{mentionHighlights.hasHighlights && (
|
{mentionHighlights.hasHighlights && (
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ Rowboat is an agentic assistant for everyday work - emails, meetings, projects,
|
||||||
|
|
||||||
**Meeting Prep:** When users ask you to prepare for a meeting, prep for a call, or brief them on attendees, load the \`meeting-prep\` skill first. It provides structured guidance for gathering context about attendees from the knowledge base and creating useful meeting briefs.
|
**Meeting Prep:** When users ask you to prepare for a meeting, prep for a call, or brief them on attendees, load the \`meeting-prep\` skill first. It provides structured guidance for gathering context about attendees from the knowledge base and creating useful meeting briefs.
|
||||||
|
|
||||||
|
**Document Collaboration:** When users ask you to work on a document, collaborate on writing, create a new document, edit/refine existing notes, or say things like "let's work on [X]", "help me write [X]", "create a doc for [X]", or "let's draft [X]", you MUST load the \`doc-collab\` skill first. This is required for any document creation or editing task. The skill provides structured guidance for creating, editing, and refining documents in the knowledge base.
|
||||||
|
|
||||||
## Memory That Compounds
|
## Memory That Compounds
|
||||||
Unlike other AI assistants that start cold every session, you have access to a live knowledge graph that updates itself from Gmail, calendar, and meeting notes (Google Meet, Granola, Fireflies). This isn't just summaries - it's structured extraction of decisions, commitments, open questions, and context, routed to long-lived notes for each person, project, and topic.
|
Unlike other AI assistants that start cold every session, you have access to a live knowledge graph that updates itself from Gmail, calendar, and meeting notes (Google Meet, Granola, Fireflies). This isn't just summaries - it's structured extraction of decisions, commitments, open questions, and context, routed to long-lived notes for each person, project, and topic.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,232 @@
|
||||||
|
export const skill = String.raw`
|
||||||
|
# Document Collaboration Skill
|
||||||
|
|
||||||
|
You are an expert document assistant helping the user create, edit, and refine documents in their knowledge base.
|
||||||
|
|
||||||
|
## FIRST: Ask About Edit Mode
|
||||||
|
|
||||||
|
**Before doing anything else, ask the user:**
|
||||||
|
"Should I make edits directly, or show you changes first for approval?"
|
||||||
|
|
||||||
|
- **Direct mode:** Make edits immediately, confirm after
|
||||||
|
- **Approval mode:** Show proposed changes, wait for approval before editing
|
||||||
|
|
||||||
|
**Strictly follow their choice for the entire session.** Don't switch modes without asking.
|
||||||
|
|
||||||
|
## Core Principles
|
||||||
|
|
||||||
|
**Be concise and direct:**
|
||||||
|
- Don't be verbose or overly chatty
|
||||||
|
- Don't propose outlines or structures unless asked
|
||||||
|
- Don't explain what you're about to do - just do it or ask a simple question
|
||||||
|
|
||||||
|
**Don't assume, ask simply:**
|
||||||
|
- If something is unclear, ask ONE simple question
|
||||||
|
- Don't offer multiple options or explain the options
|
||||||
|
- Don't guess or make assumptions about what the user wants
|
||||||
|
|
||||||
|
**Respect edit mode:**
|
||||||
|
- In direct mode: make edits immediately, then confirm briefly
|
||||||
|
- In approval mode: show the exact change you'll make, wait for "yes"/"ok"/"do it" before editing
|
||||||
|
|
||||||
|
**Use knowledge context:**
|
||||||
|
- When the user mentions people, organizations, or projects, search the knowledge base for context
|
||||||
|
- Link to relevant notes using [[wiki-link]] syntax
|
||||||
|
- Pull in relevant facts and history
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
### Step 1: Find the Document
|
||||||
|
|
||||||
|
**IMPORTANT: Always search thoroughly before saying a document doesn't exist.**
|
||||||
|
|
||||||
|
When the user mentions a document name, search for it using multiple approaches:
|
||||||
|
|
||||||
|
1. **Search by name pattern** (handles partial matches, different cases):
|
||||||
|
\`\`\`
|
||||||
|
workspace-glob({ pattern: "knowledge/**/*[name]*", path: "knowledge/" })
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
2. **Search by content** (finds docs that mention the topic):
|
||||||
|
\`\`\`
|
||||||
|
workspace-grep({ pattern: "[name]", path: "knowledge/" })
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
3. **Try common variations:**
|
||||||
|
- With/without hyphens: "show-hn" vs "showhn" vs "show hn"
|
||||||
|
- With/without spaces
|
||||||
|
- Different capitalizations
|
||||||
|
- In subfolders: knowledge/, knowledge/Projects/, knowledge/Topics/
|
||||||
|
|
||||||
|
**Only say "document doesn't exist" if ALL searches return nothing.**
|
||||||
|
|
||||||
|
**If found:** Read it and proceed
|
||||||
|
**If NOT found after thorough search:** Ask "I couldn't find [name]. Shall I create it?"
|
||||||
|
|
||||||
|
**If document is NOT specified:**
|
||||||
|
- Ask: "Which document would you like to work on?"
|
||||||
|
|
||||||
|
**Creating new documents:**
|
||||||
|
1. Ask simply: "Shall I create [filename]?" (don't ask about location - default to \`knowledge/\` root)
|
||||||
|
2. Create it with just a title - don't pre-populate with structure or outlines
|
||||||
|
3. Ask: "What would you like in this?"
|
||||||
|
|
||||||
|
\`\`\`
|
||||||
|
workspace-createFile({
|
||||||
|
path: "knowledge/[Document Name].md",
|
||||||
|
content: "# [Document Title]\n\n"
|
||||||
|
})
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
**WRONG approach:**
|
||||||
|
- "Should this be in Projects/ or Topics/?" - don't ask, just use root
|
||||||
|
- "Here's a proposed outline..." - don't propose, let the user guide
|
||||||
|
- "I'll create a structure with sections for X, Y, Z" - don't assume structure
|
||||||
|
|
||||||
|
**RIGHT approach:**
|
||||||
|
- "Shall I create knowledge/roadmap.md?"
|
||||||
|
- *creates file with just the title*
|
||||||
|
- "Created. What would you like in this?"
|
||||||
|
|
||||||
|
### Step 2: Understand the Request
|
||||||
|
|
||||||
|
**Types of requests:**
|
||||||
|
|
||||||
|
1. **Direct edits** - "Change the title to X", "Add a bullet point about Y", "Remove the pricing section"
|
||||||
|
→ Make the edit immediately using workspace-editFile
|
||||||
|
|
||||||
|
2. **Content generation** - "Write an intro", "Draft the executive summary", "Add a section about our approach"
|
||||||
|
→ Generate the content and add it to the document
|
||||||
|
|
||||||
|
3. **Review/feedback** - "What do you think?", "Is this clear?", "Any suggestions?"
|
||||||
|
→ Read the document and provide thoughtful feedback
|
||||||
|
|
||||||
|
4. **Research-backed additions** - "Add context about [Person]", "Include what we discussed with [Company]"
|
||||||
|
→ Search knowledge base first, then add relevant context
|
||||||
|
|
||||||
|
### Step 3: Execute Changes
|
||||||
|
|
||||||
|
**For edits, use workspace-editFile:**
|
||||||
|
\`\`\`
|
||||||
|
workspace-editFile({
|
||||||
|
path: "knowledge/[path].md",
|
||||||
|
old_string: "[exact text to replace]",
|
||||||
|
new_string: "[new text]"
|
||||||
|
})
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
**For additions at the end:**
|
||||||
|
\`\`\`
|
||||||
|
workspace-editFile({
|
||||||
|
path: "knowledge/[path].md",
|
||||||
|
old_string: "[last line or section]",
|
||||||
|
new_string: "[last line or section]\n\n[new content]"
|
||||||
|
})
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
**For new sections:**
|
||||||
|
Find the right place in the document structure and insert the new section.
|
||||||
|
|
||||||
|
### Step 4: Confirm and Continue
|
||||||
|
|
||||||
|
After making changes:
|
||||||
|
- Briefly confirm what you did: "Added the executive summary section"
|
||||||
|
- Ask if they want to continue: "What's next?" or "Anything else to adjust?"
|
||||||
|
- Don't read back the entire document unless asked
|
||||||
|
|
||||||
|
## Searching Knowledge for Context
|
||||||
|
|
||||||
|
When the user mentions people, companies, or projects:
|
||||||
|
|
||||||
|
**Search for relevant notes:**
|
||||||
|
\`\`\`
|
||||||
|
workspace-grep({ pattern: "[Name]", path: "knowledge/" })
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
**Read relevant notes:**
|
||||||
|
\`\`\`
|
||||||
|
workspace-readFile("knowledge/People/[Person].md")
|
||||||
|
workspace-readFile("knowledge/Organizations/[Company].md")
|
||||||
|
workspace-readFile("knowledge/Projects/[Project].md")
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
**Use the context:**
|
||||||
|
- Reference specific facts, dates, and details
|
||||||
|
- Use [[wiki-links]] to connect to other notes
|
||||||
|
- Include relevant history and background
|
||||||
|
|
||||||
|
## Document Locations
|
||||||
|
|
||||||
|
Documents are stored in \`~/.rowboat/knowledge/\` with subfolders:
|
||||||
|
- \`People/\` - Notes about individuals
|
||||||
|
- \`Organizations/\` - Notes about companies, teams
|
||||||
|
- \`Projects/\` - Project documentation
|
||||||
|
- \`Topics/\` - Subject matter notes
|
||||||
|
- Root level for general documents
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
**Writing style:**
|
||||||
|
- Match the user's tone and style in the document
|
||||||
|
- Be concise but complete
|
||||||
|
- Use markdown formatting (headers, bullets, bold, etc.)
|
||||||
|
|
||||||
|
**Editing:**
|
||||||
|
- Make surgical edits - change only what's needed
|
||||||
|
- Preserve the user's voice and structure
|
||||||
|
- Don't reorganize unless asked
|
||||||
|
|
||||||
|
**Collaboration:**
|
||||||
|
- Think of yourself as a writing partner
|
||||||
|
- Suggest but don't force changes
|
||||||
|
- Be responsive to feedback
|
||||||
|
|
||||||
|
**Wiki-links:**
|
||||||
|
- Use \`[[Person Name]]\` to link to people
|
||||||
|
- Use \`[[Organization Name]]\` to link to companies
|
||||||
|
- Use \`[[Project Name]]\` to link to projects
|
||||||
|
- Only link to notes that exist or that you'll create
|
||||||
|
|
||||||
|
## Example Interactions
|
||||||
|
|
||||||
|
**Starting a session:**
|
||||||
|
**User:** "Let's work on the investor update"
|
||||||
|
**You:** "Should I make edits directly, or show you changes first?"
|
||||||
|
**User:** "directly is fine"
|
||||||
|
**You:** *Search for it, read it*
|
||||||
|
"Found knowledge/Investor Update Q1.md. What would you like to change?"
|
||||||
|
|
||||||
|
**Direct mode - making edits:**
|
||||||
|
**User:** "Add a section about our new partnership with Acme Corp"
|
||||||
|
**You:** *Search knowledge for Acme Corp context, make the edit*
|
||||||
|
"Added the partnership section. Anything else?"
|
||||||
|
|
||||||
|
**Approval mode - showing changes first:**
|
||||||
|
**User:** "Add a section about Acme Corp"
|
||||||
|
**You:** "I'll add this after the Overview section:
|
||||||
|
\`\`\`
|
||||||
|
## Partnership with Acme Corp
|
||||||
|
[content based on knowledge...]
|
||||||
|
\`\`\`
|
||||||
|
Ok to add?"
|
||||||
|
**User:** "yes"
|
||||||
|
**You:** *Makes the edit*
|
||||||
|
"Done. What's next?"
|
||||||
|
|
||||||
|
**Creating a new doc:**
|
||||||
|
**User:** "Create a doc for the roadmap"
|
||||||
|
**You:** "Shall I create knowledge/roadmap.md?"
|
||||||
|
**User:** "yes"
|
||||||
|
**You:** *Creates file with just title*
|
||||||
|
"Created. What would you like in this?"
|
||||||
|
|
||||||
|
**WRONG examples - don't do this:**
|
||||||
|
- "Nice, new doc time! Quick clarifier: should this be standalone or in Projects/?" ❌
|
||||||
|
- "Here's a proposed outline for the doc..." ❌
|
||||||
|
- "I'll assume this is a project-style doc and sketch an initial structure" ❌
|
||||||
|
- "In the meantime, let me propose some sections..." ❌
|
||||||
|
- Switching from approval mode to direct mode without asking ❌
|
||||||
|
- In approval mode: making edits without showing the change first ❌
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default skill;
|
||||||
|
|
@ -2,6 +2,7 @@ import path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import builtinToolsSkill from "./builtin-tools/skill.js";
|
import builtinToolsSkill from "./builtin-tools/skill.js";
|
||||||
import deletionGuardrailsSkill from "./deletion-guardrails/skill.js";
|
import deletionGuardrailsSkill from "./deletion-guardrails/skill.js";
|
||||||
|
import docCollabSkill from "./doc-collab/skill.js";
|
||||||
import draftEmailsSkill from "./draft-emails/skill.js";
|
import draftEmailsSkill from "./draft-emails/skill.js";
|
||||||
import mcpIntegrationSkill from "./mcp-integration/skill.js";
|
import mcpIntegrationSkill from "./mcp-integration/skill.js";
|
||||||
import meetingPrepSkill from "./meeting-prep/skill.js";
|
import meetingPrepSkill from "./meeting-prep/skill.js";
|
||||||
|
|
@ -28,6 +29,13 @@ type ResolvedSkill = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const definitions: SkillDefinition[] = [
|
const definitions: SkillDefinition[] = [
|
||||||
|
{
|
||||||
|
id: "doc-collab",
|
||||||
|
title: "Document Collaboration",
|
||||||
|
folder: "doc-collab",
|
||||||
|
summary: "Collaborate on documents - create, edit, and refine notes and documents in the knowledge base.",
|
||||||
|
content: docCollabSkill,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "draft-emails",
|
id: "draft-emails",
|
||||||
title: "Draft Emails",
|
title: "Draft Emails",
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ const NOTES_OUTPUT_DIR = path.join(WorkDir, 'knowledge');
|
||||||
const NOTE_CREATION_AGENT = 'note_creation';
|
const NOTE_CREATION_AGENT = 'note_creation';
|
||||||
|
|
||||||
// Configuration for the graph builder service
|
// Configuration for the graph builder service
|
||||||
const SYNC_INTERVAL_MS = 5 * 60 * 1000; // Check every 5 minutes (reduced frequency)
|
const SYNC_INTERVAL_MS = 30 * 1000; // Check every 30 seconds
|
||||||
const SOURCE_FOLDERS = [
|
const SOURCE_FOLDERS = [
|
||||||
'gmail_sync',
|
'gmail_sync',
|
||||||
'fireflies_transcripts',
|
'fireflies_transcripts',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue