mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
411ee7a60f
* show app version in devui .NET: Python: Improved Versioning for DevUI Fixes #2059 * feat: Add multimodal input support for workflows and refactor chat input This PR adds support for multimodal content (images, files) in workflow inputs and refactors the chat input into a reusable component. ## Multimodal Workflow Support - Add `isChatMessageSchema()` to detect ChatMessage input schemas - Update `RunWorkflowButton` to use `ChatMessageInput` for ChatMessage workflows - Wrap multimodal content in OpenAI message format for backend processing - Add `_is_openai_multimodal_format()` to detect OpenAI ResponseInputParam - Update `_parse_workflow_input()` to route multimodal input through existing `_convert_input_to_chat_message()` converter ## Reusable ChatMessageInput Component - Extract chat input logic from agent-view into `ChatMessageInput` component - Support file upload, drag & drop, paste handling, and attachments - Add `useDragDrop` hook for parent-level drag handling with full-area drop zones - Refactor agent-view to use the new shared component ## Other Improvements - Add `isStreaming` prop to executor nodes for animation control - Clean up unused imports and state variables in agent-view - Add tests for multimodal workflow input handling Fixes workflow input not receiving images when using AgentExecutor nodes. * add self loop edge, fix #2470 * fix test
99 lines
2.5 KiB
TypeScript
99 lines
2.5 KiB
TypeScript
/**
|
|
* useDragDrop - Hook for handling drag and drop file uploads at parent level
|
|
* Provides drag state and handlers that can be spread on a container element
|
|
*/
|
|
|
|
import { useState, useCallback, useRef } from "react";
|
|
|
|
export interface UseDragDropOptions {
|
|
/** Called when files are dropped */
|
|
onDrop?: (files: File[]) => void;
|
|
/** Whether drag/drop is disabled */
|
|
disabled?: boolean;
|
|
}
|
|
|
|
export interface UseDragDropReturn {
|
|
/** Whether a drag is currently over the drop zone */
|
|
isDragOver: boolean;
|
|
/** Files that were dropped (cleared after processing) */
|
|
droppedFiles: File[];
|
|
/** Clear the dropped files after they've been processed */
|
|
clearDroppedFiles: () => void;
|
|
/** Event handlers to spread on the container element */
|
|
dragHandlers: {
|
|
onDragEnter: (e: React.DragEvent) => void;
|
|
onDragLeave: (e: React.DragEvent) => void;
|
|
onDragOver: (e: React.DragEvent) => void;
|
|
onDrop: (e: React.DragEvent) => void;
|
|
};
|
|
}
|
|
|
|
export function useDragDrop(options: UseDragDropOptions = {}): UseDragDropReturn {
|
|
const { onDrop, disabled = false } = options;
|
|
|
|
const [isDragOver, setIsDragOver] = useState(false);
|
|
const [droppedFiles, setDroppedFiles] = useState<File[]>([]);
|
|
const dragCounterRef = useRef(0);
|
|
|
|
const handleDragEnter = useCallback((e: React.DragEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
if (disabled) return;
|
|
|
|
dragCounterRef.current++;
|
|
if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
|
|
setIsDragOver(true);
|
|
}
|
|
}, [disabled]);
|
|
|
|
const handleDragLeave = useCallback((e: React.DragEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
if (disabled) return;
|
|
|
|
dragCounterRef.current--;
|
|
if (dragCounterRef.current === 0) {
|
|
setIsDragOver(false);
|
|
}
|
|
}, [disabled]);
|
|
|
|
const handleDragOver = useCallback((e: React.DragEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}, []);
|
|
|
|
const handleDrop = useCallback((e: React.DragEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
setIsDragOver(false);
|
|
dragCounterRef.current = 0;
|
|
|
|
if (disabled) return;
|
|
|
|
const files = Array.from(e.dataTransfer.files);
|
|
if (files.length > 0) {
|
|
setDroppedFiles(files);
|
|
onDrop?.(files);
|
|
}
|
|
}, [disabled, onDrop]);
|
|
|
|
const clearDroppedFiles = useCallback(() => {
|
|
setDroppedFiles([]);
|
|
}, []);
|
|
|
|
return {
|
|
isDragOver,
|
|
droppedFiles,
|
|
clearDroppedFiles,
|
|
dragHandlers: {
|
|
onDragEnter: handleDragEnter,
|
|
onDragLeave: handleDragLeave,
|
|
onDragOver: handleDragOver,
|
|
onDrop: handleDrop,
|
|
},
|
|
};
|
|
}
|