@@ -137,6 +137,8 @@ export type ChatHost = ChatInputHistoryState & {
137137 tab ?: string ;
138138 /** Callback for slash-command side effects that need app-level access. */
139139 onSlashAction ?: ( action : string ) => void | Promise < void > ;
140+ /** Selected message to reply to (right-click / keyboard shortcut). */
141+ chatReplyTarget ?: { messageId : string ; text : string ; senderLabel ?: string | null } | null ;
140142} ;
141143
142144type ChatAgentsListSnapshot = Partial < Omit < AgentsListResult , "agents" > > & {
@@ -1872,11 +1874,14 @@ export async function handleSendChat(
18721874 }
18731875 }
18741876
1877+ const replyTarget = host . chatReplyTarget ;
1878+ const effectiveMessage = replyTarget ? prependReplyQuote ( message , replyTarget ) : message ;
1879+
18751880 const refreshSessions = shouldInterpretChatCommands && isChatResetCommand ( message ) ;
18761881 const submitKey = chatSubmitKey (
18771882 host ,
18781883 "message" ,
1879- message ,
1884+ effectiveMessage ,
18801885 attachmentsToSend ,
18811886 skillWorkshopRevision ,
18821887 ) ;
@@ -1896,7 +1901,7 @@ export async function handleSendChat(
18961901 const waitingForModel = modelSwitchReady !== true ;
18971902 const queued = enqueuePendingSendMessage (
18981903 host ,
1899- message ,
1904+ effectiveMessage ,
19001905 hasAttachments ? attachmentsToSend : undefined ,
19011906 refreshSessions ,
19021907 submittedAtMs ,
@@ -1906,7 +1911,6 @@ export async function handleSendChat(
19061911 if ( ! queued ) {
19071912 return ;
19081913 }
1909-
19101914 if ( modelSwitchReady !== true && ! ( await modelSwitchReady ) ) {
19111915 if ( host . sessionKey === submittedSessionKey ) {
19121916 cancelPendingSendBeforeRequest ( host , queued , {
@@ -1943,7 +1947,7 @@ export async function handleSendChat(
19431947 return ;
19441948 }
19451949
1946- await sendChatMessageNow ( host , message , {
1950+ const accepted = await sendChatMessageNow ( host , effectiveMessage , {
19471951 queueItemId : queued . id ,
19481952 previousDraft : cleared . previousDraft ,
19491953 restoreDraft : Boolean ( messageOverride && opts ?. restoreDraft ) ,
@@ -1953,13 +1957,41 @@ export async function handleSendChat(
19531957 refreshSessions,
19541958 submittedAtMs,
19551959 } ) ;
1960+ if (
1961+ accepted &&
1962+ replyTarget &&
1963+ host . chatReplyTarget ?. messageId === replyTarget . messageId &&
1964+ host . sessionKey === submittedSessionKey
1965+ ) {
1966+ host . chatReplyTarget = null ;
1967+ }
19561968 } ) ;
19571969}
19581970
19591971function shouldQueueLocalSlashCommand ( name : string ) : boolean {
19601972 return ! [ "stop" , "export-session" , "steer" , "redirect" , "new" ] . includes ( name ) ;
19611973}
19621974
1975+ function prependReplyQuote (
1976+ message : string ,
1977+ replyTarget : NonNullable < ChatHost [ "chatReplyTarget" ] > ,
1978+ ) : string {
1979+ const label = escapeMarkdownInline ( replyTarget . senderLabel ?? "User" ) ;
1980+ const text = replyTarget . text . trim ( ) ;
1981+ if ( ! text . includes ( "\n" ) ) {
1982+ return `> **${ label } :** ${ text } \n\n${ message } ` ;
1983+ }
1984+ const quoted = text
1985+ . split ( "\n" )
1986+ . map ( ( line ) => `> ${ line } ` )
1987+ . join ( "\n" ) ;
1988+ return `> **${ label } :**\n${ quoted } \n\n${ message } ` ;
1989+ }
1990+
1991+ function escapeMarkdownInline ( value : string ) : string {
1992+ return value . replace ( / ( [ \\ ` * _ { } [ \] ( ) # + \- . ! | > ] ) / g, "\\$1" ) ;
1993+ }
1994+
19631995// ── Slash Command Dispatch ──
19641996
19651997async function dispatchSlashCommand (
@@ -2068,6 +2100,7 @@ async function clearChatHistory(host: ChatHost) {
20682100 host . chatMessages = [ ] ;
20692101 clearCachedChatMessagesForSession ( host , host . sessionKey ) ;
20702102 host . chatSideResult = null ;
2103+ host . chatReplyTarget = null ;
20712104 reconcileChatRunLifecycle ( host as unknown as Parameters < typeof reconcileChatRunLifecycle > [ 0 ] , {
20722105 outcome : hadActiveRun ? "interrupted" : undefined ,
20732106 sessionStatus : "killed" ,
0 commit comments