mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 00:02:03 +00:00
auto send prompt
This commit is contained in:
@@ -82,10 +82,11 @@
|
||||
inputProps={{ rows: 4, placeholder, onkeydown: onKeydown }}
|
||||
/>
|
||||
<Button
|
||||
endIcon={{ icon: ArrowRight }}
|
||||
endIcon={starting ? {} : { icon: ArrowRight }}
|
||||
wrapperClasses="absolute right-2 bottom-3.5"
|
||||
variant={value.trim() ? 'accent' : 'default'}
|
||||
iconOnly
|
||||
loading={starting}
|
||||
disabled={!value.trim() || starting}
|
||||
onclick={start}
|
||||
></Button>
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
selectSession,
|
||||
sessionState,
|
||||
setSessionArchived,
|
||||
syncWorkspaceTo
|
||||
syncWorkspaceTo,
|
||||
takeAutoSendPrompt
|
||||
} from './sessionState.svelte'
|
||||
import { getOrCreateRuntime, removeSession } from './sessionRuntime.svelte'
|
||||
import { goto } from '$lib/navigation'
|
||||
@@ -73,6 +74,12 @@
|
||||
// transient draft slot (script-init: AIChatInput reads it once at mount).
|
||||
const restoredDraftPrompt = peekTransientDraftPrompt(sessionId)
|
||||
|
||||
// One-shot: a prompt this session was created to auto-send (home composer).
|
||||
// Read once at init and cleared; the effect below fires it when the chat is
|
||||
// ready. Sent through the manager, so the composer stays empty (no prefill) —
|
||||
// which is why initialInstructions is suppressed when this is set.
|
||||
const autoSendPrompt = takeAutoSendPrompt(sessionId)
|
||||
|
||||
// The workspace the session acts on, shown in the header "Acting on" strip via the shared
|
||||
// WorkspaceScopeTrigger chip. `targetId` is also the workspace the chip's ellipsis menu targets.
|
||||
const acting = $derived.by(() => {
|
||||
@@ -239,6 +246,21 @@
|
||||
setTimeout(() => chat.focusInput(), 0)
|
||||
})
|
||||
|
||||
// Auto-send the prompt this session was created with, once the chat is ready
|
||||
// (same readiness gate as the focus effect: mounted + copilot loaded). Latched
|
||||
// so it fires exactly once; guarded on an empty conversation so it can never
|
||||
// interleave with a message the user already sent.
|
||||
let autoSent = false
|
||||
$effect(() => {
|
||||
if (!autoSendPrompt || autoSent) return
|
||||
if (sessionState.currentSessionId !== sessionId) return
|
||||
if (!aiChat || !$copilotInfo.enabled) return
|
||||
if (hasFirstUserMessage) return
|
||||
autoSent = true
|
||||
const chat = aiChat
|
||||
setTimeout(() => chat.sendRequest({ instructions: autoSendPrompt }), 0)
|
||||
})
|
||||
|
||||
// True when the session committed to a workspace that's no longer in
|
||||
// the user's list (deleted / archived / access revoked). The chat is
|
||||
// disabled and SessionChangesBar shows a move/discard banner.
|
||||
@@ -414,7 +436,7 @@
|
||||
hideHeader
|
||||
hideModeSelector
|
||||
wideLayout
|
||||
initialInstructions={restoredDraftPrompt}
|
||||
initialInstructions={autoSendPrompt ? undefined : restoredDraftPrompt}
|
||||
onDraftChange={(text) => queueTransientDraftPrompt(sessionId, text)}
|
||||
forceDisabled={isUnavailable || !!session.archived}
|
||||
forceDisabledMessage={isUnavailable
|
||||
|
||||
@@ -341,6 +341,24 @@ export function peekTransientDraftPrompt(sessionId: string): string | undefined
|
||||
return transientPrompt?.sessionId === sessionId ? transientPrompt.text : undefined
|
||||
}
|
||||
|
||||
// One-shot intent to auto-send a prompt as soon as a freshly-created session's
|
||||
// chat is ready (set by startSessionWithPrompt for the home composer). Held in
|
||||
// memory only — deliberately NOT persisted, so a reload never re-fires a send
|
||||
// the user didn't just trigger. Consumed once via takeAutoSendPrompt.
|
||||
let autoSendPrompt: { sessionId: string; text: string } | undefined
|
||||
export function queueAutoSendPrompt(sessionId: string, text: string): void {
|
||||
autoSendPrompt = { sessionId, text }
|
||||
}
|
||||
|
||||
// Take (read-and-clear) the auto-send prompt for a session. One-shot: the second
|
||||
// caller — a re-mount, or a different session — gets undefined.
|
||||
export function takeAutoSendPrompt(sessionId: string): string | undefined {
|
||||
if (autoSendPrompt?.sessionId !== sessionId) return undefined
|
||||
const text = autoSendPrompt.text
|
||||
autoSendPrompt = undefined
|
||||
return text
|
||||
}
|
||||
|
||||
// Write-behind a single session record. Transient (unsent) sessions are not
|
||||
// written to IndexedDB — they live in memory plus a single localStorage draft
|
||||
// slot until materializeTransient() promotes them at first send.
|
||||
|
||||
@@ -3,7 +3,7 @@ import { goto } from '$lib/navigation'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import {
|
||||
createSession,
|
||||
queueTransientDraftPrompt,
|
||||
queueAutoSendPrompt,
|
||||
selectSession,
|
||||
sessionInCurrentFamily,
|
||||
sessionState,
|
||||
@@ -50,15 +50,15 @@ export async function enterSessionMode(opts?: { replace?: boolean }): Promise<vo
|
||||
})
|
||||
}
|
||||
|
||||
// Start a fresh AI session seeded with a prompt composed elsewhere (e.g. the
|
||||
// home page composer), then route into session mode. The prompt is queued onto
|
||||
// the transient draft so the session's chat input restores it on mount — the
|
||||
// same path a reload uses — leaving it composed-but-unsent for the user to
|
||||
// review and send. No-op routing is fine for a blank prompt; callers guard.
|
||||
// Start a fresh AI session from a prompt composed elsewhere (e.g. the home page
|
||||
// composer) and auto-send it, then route into session mode. The prompt is queued
|
||||
// as a one-shot auto-send intent that SessionWrapper fires once the session's
|
||||
// chat is ready (mounted + copilot loaded). No-op routing is fine for a blank
|
||||
// prompt; callers guard.
|
||||
export async function startSessionWithPrompt(prompt: string): Promise<void> {
|
||||
const session = createSession()
|
||||
const text = prompt.trim()
|
||||
if (text) queueTransientDraftPrompt(session.id, text)
|
||||
if (text) queueAutoSendPrompt(session.id, text)
|
||||
selectSession(session.id)
|
||||
await goto(`/sessions?session_name=${encodeURIComponent(session.name)}`)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user