Repository navigation
FEAT GUI: Import dataset prompts and conversations into chat (#2751) - #3670
Nimit Jain (Nimit3418) wants to merge 5 commits into
Conversation
|
I tried this on head Shouldn't the stored template text appear in the editable input box after this action? I would expect the import to populate it without sending anything. Am I missing a required step here? I have not confirmed the cause of this particular failure. |
… import - Group conversation turns by sequence rather than prompt_group_id (microsoft#3670) - Populate composer with template prompt and avoid collision with clean preserved drafts - Add ConfirmDialog before navigation when destination has an unsent dirty draft - Prepend imported turns to existing history when importing into current conversation - Associate editor with viewed conversation ID to prevent lifecycle discard - Start imported turns as unsaved changes to protect against accidental dismissal - Round-trip editor target and temperature in conversation edit state - Create explicit conversation before navigating for new_conversation destination - Add comprehensive integration tests covering template import from clean chat
…nd target validation - Preserve destination existing messages first and append imported history after them in current_conversation - Handle history loading errors gracefully without consuming pending import - Cover dirty-draft protection and replace confirmation across new_attack, current_conversation, and new_conversation - Track unsaved imported state explicitly in useConversationDraft lifecycle - Validate and report missing conversation targets against registry without silent fallback - Add comprehensive user journey tests for all import flows and edge cases
…and editor lifecycle
|
I have addressed all the feedback and resolved the root cause of the empty input box shown in your screenshot. The changes are organized across the following 3 commits: Commit Breakdown & Issues Addressed1.
|
| let composerDraft: ConversationImport['composerDraft'] | undefined | ||
|
|
||
| if (lastTurn.role === 'user' && turns.length > 1) { | ||
| historyTurns = turns.slice(0, -1) |
There was a problem hiding this comment.
[P1] Could we keep the final user turn in the editor's draft, or preserve it separately through Save? For an example user: A, assistant: B, user: C, this now opens an editor containing only A and B. C is restored into the main composer, but that composer is hidden while the editor is open. Clicking Save then calls restoreEditorPrompt(undefined, ...), because B is not a user message, and clears C. The user ends up with A/B saved and the actual next prompt lost. If the imported history itself ends in a user turn, Save can also mistake that earlier turn for the pending prompt. Please cover the complete import -> Save -> visible composer journey, including final-user text and attachments.
| editor.begin({ | ||
| messages: allMessages, | ||
| objective: consumed.conversation.objective ?? currentObjective, | ||
| initialObjective: consumed.conversation.objective ?? currentObjective, |
There was a problem hiding this comment.
[P2] Could initialObjective stay as the destination attack's actual objective here? For example, importing an example with objective B into an attack with objective A initializes both editor values to B. useConversationSave then sees no objective change and omits objective and expected_objective from the same-attack save request. The editor displays B, but Save silently retains A, so subsequent scoring uses a different objective from the one shown during import. Please either preserve A explicitly or treat B as a proposed change against baseline A, and check the save payload in a test.
| } | ||
| } | ||
|
|
||
| const consumed = draftHandoff.consumePendingImport(pending.id, draftAttackId, draftConversationId) |
There was a problem hiding this comment.
[P2] Could we recheck the active destination and composer revision after loading history, before consuming this import? canApplyImportNow is checked before await attacksApi.getMessages(...), but typing into the composer does not advance the handoff sequence. On an empty destination with a slow history request, the user can type a new prompt while this is pending; the continuation still consumes the import and restoreComposerDraft overwrites that text, even when replaceDirty is false. Changing the destination during the request also leaves this callback holding the old IDs. Please guard the continuation against those changes, with a deferred-request test.

Description
Closes #2751. Implements work item 7 of 17 in #2744: importing dataset prompts, multimodal messages, and multi-turn conversations into the chat interface without manual copy-pasting, reattaching media, or issuing extra model calls.
Key Changes
Shared Contract (
types/index.ts):PendingImportPayloadwith an optional typedconversation?: PendingImportConversationcarrying ordered turns, objective metadata, and system prompt.ChatDraftContentwithconversation?: ConversationEditStateto protect in-progress conversation-editor drafts across navigation round-trips.Pure Data Transformation (
utils/seedImport.ts):buildSeedImport(members)to transform dataset detailSeedRecord[]into either a single composer prompt or a multi-turn conversation draft.seed_type === 'objective'into objective metadata rather than conversation turns.simulated_conversationconfigs with explicit explanation.prompt_group_idandsequence.simulated_assistant,simulated_tool).source_piece_id.Draft Handoff & Preservation (
utils/chatDraft.ts,hooks/useChatDraftHandoff.tsx):isChatDraftDirtyandhasChatDraftStatenow recognize active conversation drafts.canApplyPendingImportvalidates all three destinations:new_attack,current_conversation, andnew_conversation.Datasets UI (
SeedExampleDetail.tsx,SeedExampleBrowser.tsx):Chat View (
ChatWindow.tsx):ConversationEditordrafts on unmount when exploring Datasets.editor.begin().Documentation (
doc/gui/0_gui.md):Test Coverage
src/utils/seedImport.test.ts(11 tests).useChatDraftHandoff.test.tsx,SeedExampleDetail.test.tsx, andApp.drafts.test.tsxfor round-trip integration across all destinations.npx tsc --noEmitpassed with 0 errors.npm run lintpassed with 0 errors, 0 warnings.Screenshots
Captured from commit
ad85b3e774a669057e6e790cdf68d1bb8b043e66using Chromium and the real local backend with the isolated offline browser configuration. API responses were not mocked, and no prompt was sent.Dataset example and import destinations
The stored
wikipedia with titleexample exposes the Import into Chat menu. With no saved attack active, Import to new attack is available; the other two destinations are disabled.Observed result after Import to new attack
Known issue reproduced during capture: the app navigates to Chat, but the composer remains empty. The expected result is the selected template text in the editable input box, without sending it. This screenshot records the observed behavior, not a successful import. The empty composer was also observed after waiting 45 seconds in the initial capture attempt.