Refine chat tool status dedupe (#786)
Co-authored-by: zuolingxuan <zuolingxuan@bytedance.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
32d14b8cf9
commit
25b13ab912
@@ -75,6 +75,13 @@ function upsertImageCacheEntry(filePath: string, file: Omit<AttachedFileMeta, 'f
|
||||
saveImageCache(_imageCache);
|
||||
}
|
||||
|
||||
function withAttachedFileSource(
|
||||
file: AttachedFileMeta,
|
||||
source: AttachedFileMeta['source'],
|
||||
): AttachedFileMeta {
|
||||
return file.source ? file : { ...file, source };
|
||||
}
|
||||
|
||||
/** Extract plain text from message content (string or content blocks) */
|
||||
function getMessageText(content: unknown): string {
|
||||
if (typeof content === 'string') return content;
|
||||
@@ -228,11 +235,14 @@ function extractImagesAsAttachedFiles(content: unknown): AttachedFileMeta[] {
|
||||
/**
|
||||
* Build an AttachedFileMeta entry for a file ref, using cache if available.
|
||||
*/
|
||||
function makeAttachedFile(ref: { filePath: string; mimeType: string }): AttachedFileMeta {
|
||||
function makeAttachedFile(
|
||||
ref: { filePath: string; mimeType: string },
|
||||
source: AttachedFileMeta['source'] = 'message-ref',
|
||||
): AttachedFileMeta {
|
||||
const cached = _imageCache.get(ref.filePath);
|
||||
if (cached) return { ...cached, filePath: ref.filePath };
|
||||
if (cached) return { ...cached, filePath: ref.filePath, source };
|
||||
const fileName = ref.filePath.split(/[\\/]/).pop() || 'file';
|
||||
return { fileName, mimeType: ref.mimeType, fileSize: 0, preview: null, filePath: ref.filePath };
|
||||
return { fileName, mimeType: ref.mimeType, fileSize: 0, preview: null, filePath: ref.filePath, source };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,7 +355,7 @@ function enrichWithToolResultFiles(messages: RawMessage[]): RawMessage[] {
|
||||
}
|
||||
}
|
||||
}
|
||||
pending.push(...imageFiles);
|
||||
pending.push(...imageFiles.map((file) => withAttachedFileSource(file, 'tool-result')));
|
||||
|
||||
// 2. [media attached: ...] patterns in tool result text output
|
||||
const text = getMessageText(msg.content);
|
||||
@@ -353,12 +363,12 @@ function enrichWithToolResultFiles(messages: RawMessage[]): RawMessage[] {
|
||||
const mediaRefs = extractMediaRefs(text);
|
||||
const mediaRefPaths = new Set(mediaRefs.map(r => r.filePath));
|
||||
for (const ref of mediaRefs) {
|
||||
pending.push(makeAttachedFile(ref));
|
||||
pending.push(makeAttachedFile(ref, 'tool-result'));
|
||||
}
|
||||
// 3. Raw file paths in tool result text (documents, audio, video, etc.)
|
||||
for (const ref of extractRawFilePaths(text)) {
|
||||
if (!mediaRefPaths.has(ref.filePath)) {
|
||||
pending.push(makeAttachedFile(ref));
|
||||
pending.push(makeAttachedFile(ref, 'tool-result'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,9 +445,9 @@ function enrichWithCachedImages(messages: RawMessage[]): RawMessage[] {
|
||||
|
||||
const files: AttachedFileMeta[] = allRefs.map(ref => {
|
||||
const cached = _imageCache.get(ref.filePath);
|
||||
if (cached) return { ...cached, filePath: ref.filePath };
|
||||
if (cached) return { ...cached, filePath: ref.filePath, source: 'message-ref' };
|
||||
const fileName = ref.filePath.split(/[\\/]/).pop() || 'file';
|
||||
return { fileName, mimeType: ref.mimeType, fileSize: 0, preview: null, filePath: ref.filePath };
|
||||
return { fileName, mimeType: ref.mimeType, fileSize: 0, preview: null, filePath: ref.filePath, source: 'message-ref' };
|
||||
});
|
||||
return { ...msg, _attachedFiles: files };
|
||||
});
|
||||
|
||||
@@ -86,9 +86,8 @@ export function handleRuntimeEventState(
|
||||
: undefined;
|
||||
|
||||
// Mirror enrichWithToolResultFiles: collect images + file refs for next assistant msg
|
||||
const toolFiles: AttachedFileMeta[] = [
|
||||
...extractImagesAsAttachedFiles(finalMsg.content),
|
||||
];
|
||||
const toolFiles: AttachedFileMeta[] = extractImagesAsAttachedFiles(finalMsg.content)
|
||||
.map((file) => (file.source ? file : { ...file, source: 'tool-result' }));
|
||||
if (matchedPath) {
|
||||
for (const f of toolFiles) {
|
||||
if (!f.filePath) {
|
||||
@@ -101,9 +100,9 @@ export function handleRuntimeEventState(
|
||||
if (text) {
|
||||
const mediaRefs = extractMediaRefs(text);
|
||||
const mediaRefPaths = new Set(mediaRefs.map(r => r.filePath));
|
||||
for (const ref of mediaRefs) toolFiles.push(makeAttachedFile(ref));
|
||||
for (const ref of mediaRefs) toolFiles.push(makeAttachedFile(ref, 'tool-result'));
|
||||
for (const ref of extractRawFilePaths(text)) {
|
||||
if (!mediaRefPaths.has(ref.filePath)) toolFiles.push(makeAttachedFile(ref));
|
||||
if (!mediaRefPaths.has(ref.filePath)) toolFiles.push(makeAttachedFile(ref, 'tool-result'));
|
||||
}
|
||||
}
|
||||
set((s) => {
|
||||
|
||||
@@ -94,6 +94,7 @@ export function createRuntimeSendActions(set: ChatSet, get: ChatGet): Pick<Runti
|
||||
fileSize: a.fileSize,
|
||||
preview: a.preview,
|
||||
filePath: a.stagedPath,
|
||||
source: 'user-upload',
|
||||
})),
|
||||
};
|
||||
set((s) => ({
|
||||
|
||||
@@ -5,6 +5,7 @@ export interface AttachedFileMeta {
|
||||
fileSize: number;
|
||||
preview: string | null;
|
||||
filePath?: string;
|
||||
source?: 'user-upload' | 'tool-result' | 'message-ref';
|
||||
}
|
||||
|
||||
/** Raw message from OpenClaw chat.history */
|
||||
|
||||
Reference in New Issue
Block a user