add skills to the chat composer (#8881)
Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import type { ChatSkillDraft } from "../types";
|
||||
import type { ChatAttachmentDraft } from "@/shared/types/messages";
|
||||
import type { ChatSendOptions } from "../types";
|
||||
import { INITIAL_TOKEN_STATE } from "@/shared/types/chat";
|
||||
import { useChat } from "./useChat";
|
||||
import { useAutoCompactPreferences } from "./useAutoCompactPreferences";
|
||||
@@ -36,6 +38,7 @@ interface UseChatSessionControllerOptions {
|
||||
}
|
||||
|
||||
const PENDING_HOME_SESSION_ID = "__home_pending__";
|
||||
const EMPTY_SKILL_DRAFTS: ChatSkillDraft[] = [];
|
||||
|
||||
export function useChatSessionController({
|
||||
sessionId,
|
||||
@@ -71,6 +74,10 @@ export function useChatSessionController({
|
||||
const pendingDraftValue = useChatStore(
|
||||
(s) => s.draftsBySession[PENDING_HOME_SESSION_ID] ?? "",
|
||||
);
|
||||
const pendingSkillDrafts = useChatStore(
|
||||
(s) =>
|
||||
s.skillDraftsBySession[PENDING_HOME_SESSION_ID] ?? EMPTY_SKILL_DRAFTS,
|
||||
);
|
||||
const pendingQueuedMessage = useChatStore(
|
||||
(s) => s.queuedMessageBySession[PENDING_HOME_SESSION_ID] ?? null,
|
||||
);
|
||||
@@ -478,9 +485,14 @@ export function useChatSessionController({
|
||||
text: string,
|
||||
overridePersona?: { id: string; name?: string },
|
||||
attachments?: ChatAttachmentDraft[],
|
||||
sendOptions?: ChatSendOptions,
|
||||
) => {
|
||||
if (!canAutoCompactBeforeSend(overridePersona)) {
|
||||
void sendMessage(text, overridePersona, attachments);
|
||||
if (sendOptions) {
|
||||
void sendMessage(text, overridePersona, attachments, sendOptions);
|
||||
} else {
|
||||
void sendMessage(text, overridePersona, attachments);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -490,7 +502,11 @@ export function useChatSessionController({
|
||||
return false;
|
||||
}
|
||||
|
||||
void sendMessage(text, overridePersona, attachments);
|
||||
if (sendOptions) {
|
||||
void sendMessage(text, overridePersona, attachments, sendOptions);
|
||||
} else {
|
||||
void sendMessage(text, overridePersona, attachments);
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
},
|
||||
@@ -505,6 +521,7 @@ export function useChatSessionController({
|
||||
const deferredSend = useRef<{
|
||||
text: string;
|
||||
attachments?: ChatAttachmentDraft[];
|
||||
sendOptions?: ChatSendOptions;
|
||||
resolve?: (accepted: boolean) => void;
|
||||
} | null>(null);
|
||||
const queue = useMessageQueue(
|
||||
@@ -514,10 +531,15 @@ export function useChatSessionController({
|
||||
);
|
||||
|
||||
const handleSend = useCallback(
|
||||
(text: string, personaId?: string, attachments?: ChatAttachmentDraft[]) => {
|
||||
(
|
||||
text: string,
|
||||
personaId?: string,
|
||||
attachments?: ChatAttachmentDraft[],
|
||||
sendOptions?: ChatSendOptions,
|
||||
) => {
|
||||
if (!sessionId) {
|
||||
if (!queue.queuedMessage) {
|
||||
queue.enqueue(text, personaId, attachments);
|
||||
queue.enqueue(text, personaId, attachments, sendOptions);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -525,16 +547,16 @@ export function useChatSessionController({
|
||||
if (personaId && personaId !== selectedPersonaId) {
|
||||
handlePersonaChange(personaId);
|
||||
return new Promise<boolean>((resolve) => {
|
||||
deferredSend.current = { text, attachments, resolve };
|
||||
deferredSend.current = { text, attachments, sendOptions, resolve };
|
||||
});
|
||||
}
|
||||
|
||||
if (chatState !== "idle" && !queue.queuedMessage) {
|
||||
queue.enqueue(text, personaId, attachments);
|
||||
queue.enqueue(text, personaId, attachments, sendOptions);
|
||||
return true;
|
||||
}
|
||||
|
||||
return sendWithAutoCompact(text, undefined, attachments);
|
||||
return sendWithAutoCompact(text, undefined, attachments, sendOptions);
|
||||
},
|
||||
[
|
||||
chatState,
|
||||
@@ -548,9 +570,14 @@ export function useChatSessionController({
|
||||
|
||||
useEffect(() => {
|
||||
if (deferredSend.current && selectedPersona) {
|
||||
const { text, attachments, resolve } = deferredSend.current;
|
||||
const { text, attachments, sendOptions, resolve } = deferredSend.current;
|
||||
deferredSend.current = null;
|
||||
const sendResult = sendWithAutoCompact(text, undefined, attachments);
|
||||
const sendResult = sendWithAutoCompact(
|
||||
text,
|
||||
undefined,
|
||||
attachments,
|
||||
sendOptions,
|
||||
);
|
||||
if (sendResult instanceof Promise) {
|
||||
void sendResult.then((accepted) => {
|
||||
if (accepted === false) {
|
||||
@@ -575,13 +602,25 @@ export function useChatSessionController({
|
||||
const sessionDraftValue = useChatStore((s) =>
|
||||
sessionId ? (s.draftsBySession[sessionId] ?? "") : "",
|
||||
);
|
||||
const sessionSkillDrafts = useChatStore((s) =>
|
||||
sessionId
|
||||
? (s.skillDraftsBySession[sessionId] ?? EMPTY_SKILL_DRAFTS)
|
||||
: EMPTY_SKILL_DRAFTS,
|
||||
);
|
||||
const draftValue = sessionId ? sessionDraftValue : pendingDraftValue;
|
||||
const selectedSkills = sessionId ? sessionSkillDrafts : pendingSkillDrafts;
|
||||
const handleDraftChange = useCallback(
|
||||
(text: string) => {
|
||||
useChatStore.getState().setDraft(stateSessionId, text);
|
||||
},
|
||||
[stateSessionId],
|
||||
);
|
||||
const handleSkillsChange = useCallback(
|
||||
(skills: typeof selectedSkills) => {
|
||||
useChatStore.getState().setSkillDrafts(stateSessionId, skills);
|
||||
},
|
||||
[stateSessionId],
|
||||
);
|
||||
const scrollTarget = useChatStore((s) =>
|
||||
sessionId ? (s.scrollTargetMessageBySession[sessionId] ?? null) : null,
|
||||
);
|
||||
@@ -599,16 +638,25 @@ export function useChatSessionController({
|
||||
|
||||
let cancelled = false;
|
||||
void pendingDraftValue;
|
||||
void pendingSkillDrafts;
|
||||
void pendingQueuedMessage;
|
||||
|
||||
const syncPendingHomeState = async () => {
|
||||
const chatState = useChatStore.getState();
|
||||
const pendingDraft =
|
||||
chatState.draftsBySession[PENDING_HOME_SESSION_ID] ?? "";
|
||||
const pendingSkills =
|
||||
chatState.skillDraftsBySession[PENDING_HOME_SESSION_ID] ?? [];
|
||||
|
||||
if (pendingDraft && !chatState.draftsBySession[sessionId]) {
|
||||
chatState.setDraft(sessionId, pendingDraft);
|
||||
}
|
||||
if (
|
||||
pendingSkills.length > 0 &&
|
||||
!chatState.skillDraftsBySession[sessionId]?.length
|
||||
) {
|
||||
chatState.setSkillDrafts(sessionId, pendingSkills);
|
||||
}
|
||||
|
||||
const hasPendingProvider = pendingProviderId !== undefined;
|
||||
const hasPendingPersona = pendingPersonaId !== undefined;
|
||||
@@ -704,6 +752,7 @@ export function useChatSessionController({
|
||||
}
|
||||
|
||||
useChatStore.getState().clearDraft(PENDING_HOME_SESSION_ID);
|
||||
useChatStore.getState().clearSkillDrafts(PENDING_HOME_SESSION_ID);
|
||||
useChatStore.getState().dismissQueuedMessage(PENDING_HOME_SESSION_ID);
|
||||
useChatStore.getState().cleanupSession(PENDING_HOME_SESSION_ID);
|
||||
};
|
||||
@@ -716,6 +765,7 @@ export function useChatSessionController({
|
||||
}, [
|
||||
activeWorkspace?.path,
|
||||
pendingDraftValue,
|
||||
pendingSkillDrafts,
|
||||
pendingModelSelection,
|
||||
pendingPersonaId,
|
||||
pendingProjectId,
|
||||
@@ -750,6 +800,8 @@ export function useChatSessionController({
|
||||
handleSend,
|
||||
draftValue,
|
||||
handleDraftChange,
|
||||
selectedSkills,
|
||||
handleSkillsChange,
|
||||
scrollTarget,
|
||||
handleScrollTargetHandled,
|
||||
projectMetadataPending,
|
||||
|
||||
Reference in New Issue
Block a user