mirror of
https://github.com/EthanMarti/infio-copilot.git
synced 2026-01-17 08:35:10 +00:00
add copy and create new note button in chat view
This commit is contained in:
parent
9488146162
commit
b5766e50b2
@ -868,7 +868,6 @@ const Chat = forwardRef<ChatRef, ChatProps>((props, ref) => {
|
|||||||
>
|
>
|
||||||
{message.content}
|
{message.content}
|
||||||
</ReactMarkdownItem>
|
</ReactMarkdownItem>
|
||||||
{/* {message.content && <AssistantMessageActions key={"actions-" + message.id} message={message} />} */}
|
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { FolderOpen } from 'lucide-react'
|
import { FileSearch } from 'lucide-react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { useApp } from '../../contexts/AppContext'
|
import { useApp } from '../../contexts/AppContext'
|
||||||
@ -44,7 +44,7 @@ export default function MarkdownRegexSearchFilesBlock({
|
|||||||
>
|
>
|
||||||
<div className={'infio-chat-code-block-header'}>
|
<div className={'infio-chat-code-block-header'}>
|
||||||
<div className={'infio-chat-code-block-header-filename'}>
|
<div className={'infio-chat-code-block-header-filename'}>
|
||||||
<FolderOpen size={14} className="infio-chat-code-block-header-icon" />
|
<FileSearch size={14} className="infio-chat-code-block-header-icon" />
|
||||||
<span>regex search files "{regex}" in {path}</span>
|
<span>regex search files "{regex}" in {path}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { FolderOpen } from 'lucide-react'
|
import { FileSearch } from 'lucide-react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { useApp } from '../../contexts/AppContext'
|
import { useApp } from '../../contexts/AppContext'
|
||||||
@ -43,7 +43,7 @@ export default function MarkdownSemanticSearchFilesBlock({
|
|||||||
>
|
>
|
||||||
<div className={'infio-chat-code-block-header'}>
|
<div className={'infio-chat-code-block-header'}>
|
||||||
<div className={'infio-chat-code-block-header-filename'}>
|
<div className={'infio-chat-code-block-header-filename'}>
|
||||||
<FolderOpen size={14} className="infio-chat-code-block-header-icon" />
|
<FileSearch size={14} className="infio-chat-code-block-header-icon" />
|
||||||
<span>semantic search files "{query}" in {path}</span>
|
<span>semantic search files "{query}" in {path}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,16 +1,100 @@
|
|||||||
import { CircleCheckBig, CircleHelp } from 'lucide-react';
|
import * as Tooltip from '@radix-ui/react-tooltip';
|
||||||
import { ComponentPropsWithoutRef } from 'react';
|
import { Check, CircleCheckBig, CircleHelp, CopyIcon, FilePlus2 } from 'lucide-react';
|
||||||
|
import { ComponentPropsWithoutRef, useState } from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import rehypeRaw from 'rehype-raw';
|
import rehypeRaw from 'rehype-raw';
|
||||||
|
import { useApp } from 'src/contexts/AppContext';
|
||||||
|
|
||||||
|
|
||||||
|
function CopyButton({ message }: { message: string }) {
|
||||||
|
const [copied, setCopied] = useState(false)
|
||||||
|
|
||||||
|
const handleCopy = async () => {
|
||||||
|
await navigator.clipboard.writeText(message.trim())
|
||||||
|
setCopied(true)
|
||||||
|
setTimeout(() => {
|
||||||
|
setCopied(false)
|
||||||
|
}, 1500)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip.Provider delayDuration={0}>
|
||||||
|
<Tooltip.Root>
|
||||||
|
<Tooltip.Trigger asChild>
|
||||||
|
<button>
|
||||||
|
{copied ? (
|
||||||
|
<Check
|
||||||
|
size={12}
|
||||||
|
className="infio-chat-message-actions-icon--copied"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<CopyIcon onClick={handleCopy} size={12} />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</Tooltip.Trigger>
|
||||||
|
<Tooltip.Portal>
|
||||||
|
<Tooltip.Content className="infio-tooltip-content">
|
||||||
|
Copy message
|
||||||
|
</Tooltip.Content>
|
||||||
|
</Tooltip.Portal>
|
||||||
|
</Tooltip.Root>
|
||||||
|
</Tooltip.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CreateNewFileButton({ message }: { message: string }) {
|
||||||
|
const app = useApp()
|
||||||
|
const [created, setCreated] = useState(false)
|
||||||
|
|
||||||
|
const handleCreate = async () => {
|
||||||
|
const firstLine = message.split('\n')[0].trim().replace(/[\\\/:]/g, '');
|
||||||
|
const filename = firstLine.slice(0, 200) + (firstLine.length > 200 ? '...' : '') || 'untitled';
|
||||||
|
console.log('filename', filename)
|
||||||
|
console.log('message', message)
|
||||||
|
await app.vault.create(`/${filename}.md`, message)
|
||||||
|
setCreated(true)
|
||||||
|
setTimeout(() => {
|
||||||
|
setCreated(false)
|
||||||
|
}, 1500)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Tooltip.Provider delayDuration={0}>
|
||||||
|
<Tooltip.Root>
|
||||||
|
<Tooltip.Trigger asChild>
|
||||||
|
<button style={{ color: '#008000' }}>
|
||||||
|
{created ? (
|
||||||
|
<Check
|
||||||
|
size={12}
|
||||||
|
className="infio-chat-message-actions-icon--copied"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FilePlus2 onClick={handleCreate} size={12} />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</Tooltip.Trigger>
|
||||||
|
<Tooltip.Portal>
|
||||||
|
<Tooltip.Content className="infio-tooltip-content">
|
||||||
|
Create new note
|
||||||
|
</Tooltip.Content>
|
||||||
|
</Tooltip.Portal>
|
||||||
|
</Tooltip.Root>
|
||||||
|
</Tooltip.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const MarkdownWithIcons = ({ markdownContent, className }: { markdownContent: string, className?: string }) => {
|
const MarkdownWithIcons = ({ markdownContent, className }: { markdownContent: string, className?: string }) => {
|
||||||
// 预处理markdown内容,将<icon>标签转换为ReactMarkdown可以处理的格式
|
// 预处理markdown内容,将<icon>标签转换为ReactMarkdown可以处理的格式
|
||||||
const processedContent = markdownContent.replace(
|
const processedContent = markdownContent.replace(
|
||||||
/<icon\s+name=['"]([^'"]+)['"]\s+size=\{(\d+)\}(\s+className=['"]([^'"]+)['"])?[^>]*\/>/g,
|
/<icon\s+name=['"]([^'"]+)['"]\s+size=\{(\d+)\}(\s+className=['"]([^'"]+)['"])?[^>]*\/>/g,
|
||||||
(_, name, size, __, className) =>
|
(_, name, size, __, className) =>
|
||||||
`<span data-icon="${name}" data-size="${size}" ${className ? `class="${className}"` : ''}></span>`
|
`<span data-icon="${name}" data-size="${size}" ${className ? `class="${className}"` : ''}></span>`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const rawContent = markdownContent.replace(
|
||||||
|
/<icon\s+name=['"]([^'"]+)['"]\s+size=\{(\d+)\}(\s+className=['"]([^'"]+)['"])?[^>]*\/>/g,
|
||||||
|
() => ``
|
||||||
|
).trim();
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
span: (props: ComponentPropsWithoutRef<'span'> & {
|
span: (props: ComponentPropsWithoutRef<'span'> & {
|
||||||
'data-icon'?: string;
|
'data-icon'?: string;
|
||||||
@ -20,7 +104,7 @@ const MarkdownWithIcons = ({ markdownContent, className }: { markdownContent: st
|
|||||||
const name = props['data-icon'];
|
const name = props['data-icon'];
|
||||||
const size = props['data-size'] ? Number(props['data-size']) : 16;
|
const size = props['data-size'] ? Number(props['data-size']) : 16;
|
||||||
const className = props.className || '';
|
const className = props.className || '';
|
||||||
|
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'ask_followup_question':
|
case 'ask_followup_question':
|
||||||
return <CircleHelp size={size} className={className} />;
|
return <CircleHelp size={size} className={className} />;
|
||||||
@ -35,13 +119,21 @@ const MarkdownWithIcons = ({ markdownContent, className }: { markdownContent: st
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactMarkdown
|
<>
|
||||||
className={`${className}`}
|
<ReactMarkdown
|
||||||
components={components}
|
className={`${className}`}
|
||||||
rehypePlugins={[rehypeRaw]}
|
components={components}
|
||||||
>
|
rehypePlugins={[rehypeRaw]}
|
||||||
{processedContent}
|
>
|
||||||
</ReactMarkdown>
|
{processedContent}
|
||||||
|
</ReactMarkdown>
|
||||||
|
{processedContent &&
|
||||||
|
<div className="infio-chat-message-actions">
|
||||||
|
<CopyButton message={rawContent} />
|
||||||
|
<CreateNewFileButton message={rawContent} />
|
||||||
|
</div>}
|
||||||
|
</>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
|
|||||||
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
|
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
|
||||||
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within <thinking></thinking> tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Then, think about which of the provided tools is the most relevant tool to accomplish the user's task. Next, go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
|
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within <thinking></thinking> tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Then, think about which of the provided tools is the most relevant tool to accomplish the user's task. Next, go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
|
||||||
4. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
|
4. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
|
||||||
`
|
5. When referencing web pages, use Markdown-style links: [display text](url).`
|
||||||
}
|
}
|
||||||
|
|
||||||
function getObsidianObjectiveSection(): string {
|
function getObsidianObjectiveSection(): string {
|
||||||
@ -23,7 +23,10 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
|
|||||||
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
|
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
|
||||||
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
|
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
|
||||||
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within <thinking></thinking> tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Then, think about which of the provided tools is the most relevant tool to accomplish the user's task. Next, go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
|
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within <thinking></thinking> tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Then, think about which of the provided tools is the most relevant tool to accomplish the user's task. Next, go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
|
||||||
4. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.`
|
4. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
|
||||||
|
5. When referencing files, use Markdown-style links: [display text](file-path.md). Follow these rules:
|
||||||
|
- Always use full relative paths (e.g., [Daily/2024-04/26.md](Daily/2024-04/26.md)
|
||||||
|
- Never use bare filenames without links (e.g., ✗ "26.md")`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getObjectiveSection(mode: string): string {
|
export function getObjectiveSection(mode: string): string {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import {
|
|||||||
MentionableVault
|
MentionableVault
|
||||||
} from '../types/mentionable'
|
} from '../types/mentionable'
|
||||||
import { InfioSettings } from '../types/settings'
|
import { InfioSettings } from '../types/settings'
|
||||||
import { Mode, defaultModeSlug, getFullModeDetails, getModeBySlug } from "../utils/modes"
|
import { Mode, getFullModeDetails } from "../utils/modes"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
readTFileContent
|
readTFileContent
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user