diff --git a/src/automats/chatAutomat.js b/src/automats/chatAutomat.js
index d93fda5..e16ee44 100644
--- a/src/automats/chatAutomat.js
+++ b/src/automats/chatAutomat.js
@@ -331,9 +331,13 @@ const actions = {
/**
* Stage an extracted text snippet (e.g. from an invoice or delivery document) as a pill.
- * @param {{ text: string, label?: string }} snippet
+ * @param {{ text: string, label?: string, instruction?: string }} snippet
*/
- insertExtractionSnippet({ text = '', label = 'parsed invoice' } = {}) {
+ insertExtractionSnippet({
+ text = '',
+ label = 'parsed invoice',
+ instruction = "use 'Process Incoming Product and Invoices' SKILL to fill drafts/delivery vfs file",
+ } = {}) {
const trimmed = String(text || '').trim();
if (!trimmed) return;
chatOpenedThisSession = true;
@@ -343,6 +347,7 @@ const actions = {
pendingExtraction: {
text: trimmed,
label: label || 'parsed invoice',
+ instruction: instruction || "use 'Process Incoming Product and Invoices' SKILL to fill drafts/delivery vfs file",
},
});
ensureCompanyEventsConnected();
diff --git a/src/components/chat/ChatDrawer.jsx b/src/components/chat/ChatDrawer.jsx
index a9ce16d..1e2f735 100644
--- a/src/components/chat/ChatDrawer.jsx
+++ b/src/components/chat/ChatDrawer.jsx
@@ -20,7 +20,12 @@ import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined';
import Tooltip from '@mui/material/Tooltip';
import Badge from '@mui/material/Badge';
import Divider from '@mui/material/Divider';
+import Dialog from '@mui/material/Dialog';
+import DialogTitle from '@mui/material/DialogTitle';
+import DialogContent from '@mui/material/DialogContent';
+import DialogActions from '@mui/material/DialogActions';
import AttachFileRoundedIcon from '@mui/icons-material/AttachFileRounded';
+import ContentCopyRoundedIcon from '@mui/icons-material/ContentCopyRounded';
import TuneRoundedIcon from '@mui/icons-material/TuneRounded';
import ElderlyRoundedIcon from '@mui/icons-material/ElderlyRounded';
import DirectionsWalkRoundedIcon from '@mui/icons-material/DirectionsWalkRounded';
@@ -47,6 +52,7 @@ import {
} from '../../colors';
const DEFAULT_DRAWER_WIDTH = 460;
+const EXTRACTION_MODEL_INSTRUCTION = "use 'Process Incoming Product and Invoices' SKILL to fill drafts/delivery vfs file";
/** Sort by updated_at desc; subagents (started_by set) directly below their parent. */
function sortConversations(list) {
@@ -122,9 +128,11 @@ export default class ChatDrawer extends PureComponent {
id: `ext-${Date.now()}`,
text: s.pendingExtraction.text,
label: s.pendingExtraction.label || 'parsed invoice',
+ instruction: s.pendingExtraction.instruction || EXTRACTION_MODEL_INSTRUCTION,
},
]
: [],
+ previewExtraction: null,
isProcessingFiles: false,
isDraggingFiles: false,
attachmentError: null,
@@ -234,6 +242,7 @@ export default class ChatDrawer extends PureComponent {
id: `ext-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
text: ext.text,
label: ext.label || 'parsed invoice',
+ instruction: ext.instruction || EXTRACTION_MODEL_INSTRUCTION,
};
patch.stagedExtractions = [...(this.state.stagedExtractions || []), newExt];
queueMicrotask(() => {
@@ -348,6 +357,22 @@ export default class ChatDrawer extends PureComponent {
this.focusInput(50);
};
+ handlePreviewExtraction = (ext) => {
+ console.log('[ChatDrawer] Clicked extraction pill:', ext);
+ this.setState({ previewExtraction: ext });
+ };
+
+ handleCloseExtractionPreview = () => {
+ this.setState({ previewExtraction: null });
+ };
+
+ handleCopyExtractionText = () => {
+ const text = this.state.previewExtraction?.text;
+ if (text && navigator?.clipboard?.writeText) {
+ navigator.clipboard.writeText(text);
+ }
+ };
+
handleVfsResizerStart = (e) => {
if (e.button !== undefined && e.button !== 0) return;
e.preventDefault();
@@ -534,10 +559,22 @@ export default class ChatDrawer extends PureComponent {
let text = rawText;
if (extractions.length > 0) {
+ const instructions = extractions
+ .map((e) => e.instruction)
+ .filter(Boolean);
+ const uniqueInstructions = Array.from(new Set(instructions));
+ const instructionText =
+ uniqueInstructions.join('\n\n') || EXTRACTION_MODEL_INSTRUCTION;
+
const extMarkdown = extractions
.map((ext) => `\`\`\`\n${ext.text.trim()}\n\`\`\``)
.join('\n\n');
- text = text ? `${extMarkdown}\n\n${text}` : extMarkdown;
+
+ if (text) {
+ text = `${instructionText}\n\n${text}\n\n${extMarkdown}`;
+ } else {
+ text = `${instructionText}\n\n${extMarkdown}`;
+ }
}
if (references.length > 0) {
@@ -1601,6 +1638,10 @@ export default class ChatDrawer extends PureComponent {
{stagedExtractions && stagedExtractions.map((ext) => (
{
+ e.stopPropagation();
+ this.handlePreviewExtraction(ext);
+ }}
sx={{
display: 'inline-flex',
alignItems: 'center',
@@ -1622,6 +1663,15 @@ export default class ChatDrawer extends PureComponent {
fontSize: '0.75rem',
lineHeight: 1.2,
userSelect: 'none',
+ cursor: 'pointer',
+ transition: 'all 0.15s ease',
+ '&:hover': {
+ bgcolor: (theme) =>
+ theme.palette.mode === 'dark'
+ ? 'rgba(255, 255, 255, 0.14)'
+ : 'rgba(0, 0, 0, 0.09)',
+ borderColor: 'primary.light',
+ },
}}
>
@@ -1921,6 +1971,71 @@ export default class ChatDrawer extends PureComponent {
{this.renderFooter()}
+
+ {/* Extraction Preview Dialog */}
+
>
);
}
diff --git a/src/components/manifest/Attachment.jsx b/src/components/manifest/Attachment.jsx
index e86d310..180ef7b 100644
--- a/src/components/manifest/Attachment.jsx
+++ b/src/components/manifest/Attachment.jsx
@@ -69,6 +69,7 @@ export class Attachment extends PureComponent {
handleMentionInChat = async (e) => {
e?.stopPropagation?.();
const { attachment, onMentionInChat } = this.props;
+ console.log('[Attachment] Mention in chat clicked', attachment);
if (!attachment) return;
if (onMentionInChat) {
@@ -105,11 +106,15 @@ export class Attachment extends PureComponent {
}
const trimmed = (textContent || '').trim();
- if (!trimmed) return;
+ if (!trimmed) {
+ console.warn('[Attachment] No text found to mention in chat', attachment);
+ return;
+ }
chatAutomat.actions.insertExtractionSnippet({
text: trimmed,
label: 'parsed invoice',
+ instruction: "use 'Process Incoming Product and Invoices' SKILL to fill drafts/delivery vfs file",
});
};
diff --git a/src/routes/lieferung/neu.jsx b/src/routes/lieferung/neu.jsx
index 4e23548..a7adc94 100644
--- a/src/routes/lieferung/neu.jsx
+++ b/src/routes/lieferung/neu.jsx
@@ -688,6 +688,7 @@ class LieferungNeuPage extends PureComponent {
}
async handleMentionInChat(attachment) {
+ console.log('[neu.jsx] handleMentionInChat called', attachment);
if (!attachment) return;
let text = attachment.text;
if (!text && (!attachment.file || attachment.file.size === 0)) {
@@ -708,11 +709,16 @@ class LieferungNeuPage extends PureComponent {
}
const trimmed = (text || '').trim();
- if (!trimmed) return;
+ if (!trimmed) {
+ console.warn('[neu.jsx] handleMentionInChat: text is empty for attachment', attachment);
+ return;
+ }
+ console.log('[neu.jsx] Inserting extraction snippet to chat, length:', trimmed.length);
chatAutomat.actions.insertExtractionSnippet({
text: trimmed,
label: 'parsed invoice',
+ instruction: "use 'Process Incoming Product and Invoices' SKILL to fill drafts/delivery vfs file",
});
}