u
This commit is contained in:
@@ -238,8 +238,8 @@ export function parseExtractionsFromText(rawText) {
|
||||
}
|
||||
|
||||
// 2. Legacy / fallback: message contains "use 'Process Incoming Product and Invoices' SKILL" + code block
|
||||
const instructionPhrase = "use 'Process Incoming Product and Invoices' SKILL to fill drafts/delivery vfs file";
|
||||
if (cleanText.includes(instructionPhrase)) {
|
||||
const hasInvoiceSkill = cleanText.includes("Process Incoming Product and Invoices");
|
||||
if (hasInvoiceSkill) {
|
||||
const codeBlockRegex = /```[a-z]*\s*\n([\s\S]*?)```/g;
|
||||
let cbMatch;
|
||||
while ((cbMatch = codeBlockRegex.exec(cleanText)) !== null) {
|
||||
|
||||
@@ -39,15 +39,12 @@ import CycloneRoundedIcon from '@mui/icons-material/CycloneRounded';
|
||||
import { setting as settingApi } from '../../api';
|
||||
import chatAutomat, {
|
||||
selectPendingAskUser,
|
||||
selectPendingDraftRead,
|
||||
} from '../../automats/chatAutomat';
|
||||
import { getActiveDraftContent } from '../../automats/draftSync';
|
||||
import userSettingsAutomat from '../../automats/userSettingsAutomat';
|
||||
import vfsAutomat from '../../automats/vfsAutomat';
|
||||
import { VfsEditorPanel, VfsFileIcon } from '../vfs';
|
||||
import ChatFlowList from './ChatFlowList';
|
||||
import AskUserPrompt from './AskUserPrompt';
|
||||
import DraftRequestPrompt from './DraftRequestPrompt';
|
||||
import { ACCEPT_STRING, readFileAttachment } from './chatAttachments';
|
||||
import { ChatStagedAttachmentsTray } from './ChatAttachmentItems';
|
||||
import {
|
||||
@@ -57,7 +54,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";
|
||||
const EXTRACTION_MODEL_INSTRUCTION = "use 'Process Incoming Product and Invoices' SKILL";
|
||||
|
||||
/** Sort by updated_at desc; subagents (started_by set) directly below their parent. */
|
||||
function sortConversations(list) {
|
||||
@@ -103,7 +100,7 @@ function conversationTitle(c) {
|
||||
.replace(/\[EXTRACTION(?:\s+label="[^"]*")?\][\s\S]*?\[\/EXTRACTION\]/gi, '')
|
||||
.replace(/<extraction(?:\s+label="[^"]*")?>[\s\S]*?<\/extraction>/gi, '')
|
||||
.replace(/```[\s\S]*?```/g, '')
|
||||
.replace(/use 'Process Incoming Product and Invoices' SKILL to fill drafts\/delivery vfs file/gi, '')
|
||||
.replace(/use 'Process Incoming Product and Invoices' SKILL.*/gi, '')
|
||||
.replace(/<USERENV>[\s\S]*?<\/USERENV>/gi, '')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
@@ -841,33 +838,7 @@ export default class ChatDrawer extends PureComponent {
|
||||
};
|
||||
|
||||
getPendingAskUser = () => selectPendingAskUser(this.state);
|
||||
getPendingDraftRead = () => selectPendingDraftRead(this.state);
|
||||
|
||||
handleProvideDraft = async ({ toolCallId, draftKey, empty = false }) => {
|
||||
try {
|
||||
let content;
|
||||
if (empty) {
|
||||
content = { error: 'Draft not open or empty' };
|
||||
} else {
|
||||
const manifest = getActiveDraftContent(draftKey);
|
||||
content = {
|
||||
manifest: manifest || {
|
||||
kind: draftKey,
|
||||
mode: 'create',
|
||||
lines: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
await chatAutomat.actions.sendToolResponse({
|
||||
tool_call_id: toolCallId,
|
||||
name: 'read_file',
|
||||
content,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('[ChatDrawer] Failed to provide draft response:', err);
|
||||
}
|
||||
};
|
||||
|
||||
renderHeader() {
|
||||
const {
|
||||
@@ -1364,7 +1335,6 @@ export default class ChatDrawer extends PureComponent {
|
||||
}
|
||||
|
||||
const pendingAsk = this.getPendingAskUser();
|
||||
const pendingDraftRead = this.getPendingDraftRead();
|
||||
|
||||
return (
|
||||
<Box sx={{ flexGrow: 1, display: 'flex', flexDirection: 'column', minHeight: 0, overflow: 'hidden' }}>
|
||||
@@ -1399,14 +1369,6 @@ export default class ChatDrawer extends PureComponent {
|
||||
disabled={this.state.isSending}
|
||||
/>
|
||||
)}
|
||||
|
||||
{pendingDraftRead && (
|
||||
<DraftRequestPrompt
|
||||
draftData={pendingDraftRead}
|
||||
onProvideDraft={this.handleProvideDraft}
|
||||
disabled={this.state.isSending}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -1429,13 +1391,11 @@ export default class ChatDrawer extends PureComponent {
|
||||
} = this.state;
|
||||
|
||||
const pendingAsk = this.getPendingAskUser();
|
||||
const pendingDraftRead = this.getPendingDraftRead();
|
||||
const isBusy = conversationState === 'busy';
|
||||
const isWorking = isBusy || isSending;
|
||||
const canChat =
|
||||
(Boolean(selectedConversationId) || draftConversation) &&
|
||||
!pendingAsk &&
|
||||
!pendingDraftRead;
|
||||
!pendingAsk;
|
||||
const canSend =
|
||||
!isWorking &&
|
||||
canChat &&
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
import React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Button from '@mui/material/Button';
|
||||
import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined';
|
||||
import SendRoundedIcon from '@mui/icons-material/SendRounded';
|
||||
import BlockRoundedIcon from '@mui/icons-material/BlockRounded';
|
||||
import { getActiveDraftContent } from '../../automats/draftSync';
|
||||
import {
|
||||
ASK_PROMPT_BG_PAIR,
|
||||
ASK_PROMPT_BORDER_PAIR,
|
||||
byMode,
|
||||
} from '../../colors';
|
||||
|
||||
export default function DraftRequestPrompt({ draftData, onProvideDraft, disabled = false }) {
|
||||
const { toolCallId, filename, draftKey } = draftData;
|
||||
const manifest = getActiveDraftContent(draftKey);
|
||||
const rawLines = manifest?.lines ?? manifest?.lineitems ?? [];
|
||||
const linesCount = Array.isArray(rawLines) ? rawLines.length : 0;
|
||||
const hasContent = Boolean(manifest && (linesCount > 0 || manifest.partyId || manifest.supplierId));
|
||||
|
||||
const handleSendDraft = () => {
|
||||
if (disabled) return;
|
||||
onProvideDraft({ toolCallId, draftKey, empty: false });
|
||||
};
|
||||
|
||||
const handleSendEmpty = () => {
|
||||
if (disabled) return;
|
||||
onProvideDraft({ toolCallId, draftKey, empty: true });
|
||||
};
|
||||
|
||||
const draftLabel =
|
||||
draftKey === 'delivery'
|
||||
? 'Lieferung'
|
||||
: draftKey === 'quote'
|
||||
? 'Angebot'
|
||||
: draftKey === 'order'
|
||||
? 'Bestellung'
|
||||
: draftKey;
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={(theme) => ({
|
||||
mx: 2,
|
||||
my: 1,
|
||||
p: 2,
|
||||
borderRadius: 3,
|
||||
bgcolor: byMode(theme, ASK_PROMPT_BG_PAIR),
|
||||
border: `1px solid ${byMode(theme, ASK_PROMPT_BORDER_PAIR)}`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 1.5,
|
||||
})}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, color: 'primary.main' }}>
|
||||
<DescriptionOutlinedIcon sx={{ fontSize: 20 }} />
|
||||
<Typography variant="subtitle2" fontWeight={700} sx={{ color: 'text.primary' }}>
|
||||
Entwurfsanfrage: {filename || `drafts/${draftKey}`}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Typography variant="body2" sx={{ color: 'text.secondary', fontSize: '0.82rem', lineHeight: 1.4 }}>
|
||||
{hasContent ? (
|
||||
<>
|
||||
Das Modell möchte den aktuellen <strong>{draftLabel}-Entwurf</strong> ({linesCount} Position{linesCount === 1 ? '' : 'en'}) einlesen, um die Bearbeitung fortzusetzen.
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Das Modell fordert <strong>{filename}</strong> an. Aktuell ist kein {draftLabel}-Entwurf geöffnet.
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1, mt: 0.5 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
disabled={disabled}
|
||||
onClick={handleSendDraft}
|
||||
startIcon={<SendRoundedIcon sx={{ fontSize: 16 }} />}
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
px: 2,
|
||||
py: 0.75,
|
||||
textTransform: 'none',
|
||||
fontSize: '0.82rem',
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{hasContent ? `Aktuellen ${draftLabel}-Entwurf senden` : 'Leeren Entwurf senden'}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
disabled={disabled}
|
||||
onClick={handleSendEmpty}
|
||||
startIcon={<BlockRoundedIcon sx={{ fontSize: 16 }} />}
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
px: 1.5,
|
||||
py: 0.75,
|
||||
textTransform: 'none',
|
||||
fontSize: '0.82rem',
|
||||
color: 'text.secondary',
|
||||
borderColor: 'divider',
|
||||
'&:hover': {
|
||||
borderColor: 'error.main',
|
||||
color: 'error.main',
|
||||
},
|
||||
}}
|
||||
>
|
||||
Nicht verfügbar melden
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -2,4 +2,3 @@ export { default as ChatFab } from './ChatFab';
|
||||
export { default as ChatDrawer } from './ChatDrawer';
|
||||
export { default as ChatFlowList } from './ChatFlowList';
|
||||
export { default as NewConversationDialog } from './NewConversationDialog';
|
||||
export { default as DraftRequestPrompt } from './DraftRequestPrompt';
|
||||
|
||||
@@ -114,7 +114,7 @@ export class Attachment extends PureComponent {
|
||||
chatAutomat.actions.insertExtractionSnippet({
|
||||
text: trimmed,
|
||||
label: 'parsed invoice',
|
||||
instruction: "use 'Process Incoming Product and Invoices' SKILL to fill drafts/delivery vfs file",
|
||||
instruction: "use 'Process Incoming Product and Invoices' SKILL",
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user