feat: add install readme et al
This commit is contained in:
@@ -56,9 +56,7 @@ interface CommandsCatalogResponse {
|
||||
}
|
||||
|
||||
function renderCommandsCatalog(catalog: CommandsCatalogResponse): string {
|
||||
const sections = catalog.categories?.length
|
||||
? catalog.categories
|
||||
: [{ name: 'Commands', pairs: catalog.pairs ?? [] }]
|
||||
const sections = catalog.categories?.length ? catalog.categories : [{ name: 'Commands', pairs: catalog.pairs ?? [] }]
|
||||
|
||||
const body = sections
|
||||
.filter(section => section.pairs.length > 0)
|
||||
@@ -120,12 +118,15 @@ export function usePromptActions({
|
||||
async (rawText: string) => {
|
||||
const visibleText = rawText.trim()
|
||||
const attachments = $composerAttachments.get()
|
||||
|
||||
const contextRefs = attachments
|
||||
.map(attachment => attachment.refText)
|
||||
.filter(Boolean)
|
||||
.join('\n')
|
||||
|
||||
const hasImageAttachment = attachments.some(attachment => attachment.kind === 'image')
|
||||
const displayRefs = attachments.map(attachmentDisplayText).filter(Boolean).join('\n')
|
||||
|
||||
const text =
|
||||
[contextRefs, visibleText].filter(Boolean).join('\n\n') ||
|
||||
(hasImageAttachment ? 'What do you see in this image?' : '')
|
||||
@@ -241,6 +242,7 @@ export function usePromptActions({
|
||||
session_id: sessionId,
|
||||
command: command.replace(/^\/+/, '')
|
||||
})
|
||||
|
||||
const body = result?.output || `/${name}: no output`
|
||||
renderSlashOutput(result?.warning ? `warning: ${result.warning}\n${body}` : body)
|
||||
|
||||
@@ -407,6 +409,7 @@ export function usePromptActions({
|
||||
|
||||
const messages = $messages.get()
|
||||
const parentIndex = parentId ? messages.findIndex(message => message.id === parentId) : messages.length - 1
|
||||
|
||||
const userIndex =
|
||||
parentIndex >= 0
|
||||
? [...messages.slice(0, parentIndex + 1)].reverse().findIndex(message => message.role === 'user')
|
||||
@@ -428,6 +431,7 @@ export function usePromptActions({
|
||||
parentId && messages[parentIndex]?.role === 'assistant'
|
||||
? messages[parentIndex]
|
||||
: messages.slice(absoluteUserIndex + 1).find(message => message.role === 'assistant')
|
||||
|
||||
const branchGroupId = targetAssistant?.branchGroupId ?? branchGroupForUser(userMessage)
|
||||
|
||||
clearNotifications()
|
||||
@@ -435,6 +439,7 @@ export function usePromptActions({
|
||||
const nextUserIndex = state.messages.findIndex(
|
||||
(message, index) => index > absoluteUserIndex && message.role === 'user'
|
||||
)
|
||||
|
||||
const end = nextUserIndex < 0 ? state.messages.length : nextUserIndex
|
||||
|
||||
return {
|
||||
|
||||
@@ -280,110 +280,121 @@ export function useSessionActions({
|
||||
]
|
||||
)
|
||||
|
||||
const branchCurrentSession = useCallback(async (messageId?: string): Promise<boolean> => {
|
||||
const sourceSessionId = activeSessionIdRef.current
|
||||
const branchCurrentSession = useCallback(
|
||||
async (messageId?: string): Promise<boolean> => {
|
||||
const sourceSessionId = activeSessionIdRef.current
|
||||
|
||||
if (!sourceSessionId) {
|
||||
notify({
|
||||
kind: 'warning',
|
||||
title: 'Nothing to branch',
|
||||
message: 'Start or resume a chat before branching.'
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
if (busyRef.current) {
|
||||
notify({
|
||||
kind: 'warning',
|
||||
title: 'Session busy',
|
||||
message: 'Stop the current turn before branching this chat.'
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
const currentMessages = $messages.get()
|
||||
const targetIndex = messageId ? currentMessages.findIndex(message => message.id === messageId) : -1
|
||||
const branchStart = targetIndex >= 0 ? targetIndex : Math.max(currentMessages.length - 1, 0)
|
||||
const branchEnd = targetIndex >= 0 ? targetIndex + 1 : currentMessages.length
|
||||
|
||||
const branchMessages = currentMessages
|
||||
.slice(branchStart, branchEnd)
|
||||
.map(message => ({
|
||||
content: chatMessageText(message),
|
||||
source: message,
|
||||
role: message.role
|
||||
}))
|
||||
.filter(message => message.content.trim() && ['assistant', 'system', 'user'].includes(message.role))
|
||||
|
||||
if (!branchMessages.length) {
|
||||
if (!sourceSessionId) {
|
||||
notify({
|
||||
kind: 'warning',
|
||||
title: 'Nothing to branch',
|
||||
message: 'This message has no text to branch from.'
|
||||
message: 'Start or resume a chat before branching.'
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
clearNotifications()
|
||||
if (busyRef.current) {
|
||||
notify({
|
||||
kind: 'warning',
|
||||
title: 'Session busy',
|
||||
message: 'Stop the current turn before branching this chat.'
|
||||
})
|
||||
|
||||
const branched = await requestGateway<SessionCreateResponse>('session.create', {
|
||||
cols: 96,
|
||||
messages: branchMessages.map(({ content, role }) => ({ content, role })),
|
||||
title: 'Branch'
|
||||
})
|
||||
|
||||
const routedSessionId = branched.stored_session_id ?? branched.session_id
|
||||
|
||||
setFreshDraftReady(false)
|
||||
ensureSessionState(branched.session_id, routedSessionId)
|
||||
setActiveSessionId(branched.session_id)
|
||||
activeSessionIdRef.current = branched.session_id
|
||||
updateSessionState(
|
||||
branched.session_id,
|
||||
state => ({
|
||||
...state,
|
||||
messages: branchMessages.map(({ source }) => source),
|
||||
busy: false,
|
||||
awaitingResponse: false
|
||||
}),
|
||||
routedSessionId
|
||||
)
|
||||
setSelectedStoredSessionId(routedSessionId)
|
||||
selectedStoredSessionIdRef.current = routedSessionId
|
||||
navigate(sessionRoute(routedSessionId))
|
||||
|
||||
clearComposerDraft()
|
||||
clearComposerAttachments()
|
||||
|
||||
if (branched.info?.model) {
|
||||
setCurrentModel(branched.info.model)
|
||||
return false
|
||||
}
|
||||
|
||||
if (branched.info?.provider) {
|
||||
setCurrentProvider(branched.info.provider)
|
||||
try {
|
||||
const currentMessages = $messages.get()
|
||||
const targetIndex = messageId ? currentMessages.findIndex(message => message.id === messageId) : -1
|
||||
const branchStart = targetIndex >= 0 ? targetIndex : Math.max(currentMessages.length - 1, 0)
|
||||
const branchEnd = targetIndex >= 0 ? targetIndex + 1 : currentMessages.length
|
||||
|
||||
const branchMessages = currentMessages
|
||||
.slice(branchStart, branchEnd)
|
||||
.map(message => ({
|
||||
content: chatMessageText(message),
|
||||
source: message,
|
||||
role: message.role
|
||||
}))
|
||||
.filter(message => message.content.trim() && ['assistant', 'system', 'user'].includes(message.role))
|
||||
|
||||
if (!branchMessages.length) {
|
||||
notify({
|
||||
kind: 'warning',
|
||||
title: 'Nothing to branch',
|
||||
message: 'This message has no text to branch from.'
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
clearNotifications()
|
||||
|
||||
const branched = await requestGateway<SessionCreateResponse>('session.create', {
|
||||
cols: 96,
|
||||
messages: branchMessages.map(({ content, role }) => ({ content, role })),
|
||||
title: 'Branch'
|
||||
})
|
||||
|
||||
const routedSessionId = branched.stored_session_id ?? branched.session_id
|
||||
|
||||
setFreshDraftReady(false)
|
||||
ensureSessionState(branched.session_id, routedSessionId)
|
||||
setActiveSessionId(branched.session_id)
|
||||
activeSessionIdRef.current = branched.session_id
|
||||
updateSessionState(
|
||||
branched.session_id,
|
||||
state => ({
|
||||
...state,
|
||||
messages: branchMessages.map(({ source }) => source),
|
||||
busy: false,
|
||||
awaitingResponse: false
|
||||
}),
|
||||
routedSessionId
|
||||
)
|
||||
setSelectedStoredSessionId(routedSessionId)
|
||||
selectedStoredSessionIdRef.current = routedSessionId
|
||||
navigate(sessionRoute(routedSessionId))
|
||||
|
||||
clearComposerDraft()
|
||||
clearComposerAttachments()
|
||||
|
||||
if (branched.info?.model) {
|
||||
setCurrentModel(branched.info.model)
|
||||
}
|
||||
|
||||
if (branched.info?.provider) {
|
||||
setCurrentProvider(branched.info.provider)
|
||||
}
|
||||
|
||||
if (branched.info?.cwd) {
|
||||
setCurrentCwd(branched.info.cwd)
|
||||
}
|
||||
|
||||
setCurrentBranch(branched.info?.branch || '')
|
||||
|
||||
if (typeof branched.info?.personality === 'string') {
|
||||
setCurrentPersonality(normalizePersonalityValue(branched.info.personality))
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (err) {
|
||||
notifyError(err, 'Branch failed')
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
if (branched.info?.cwd) {
|
||||
setCurrentCwd(branched.info.cwd)
|
||||
}
|
||||
|
||||
setCurrentBranch(branched.info?.branch || '')
|
||||
|
||||
if (typeof branched.info?.personality === 'string') {
|
||||
setCurrentPersonality(normalizePersonalityValue(branched.info.personality))
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (err) {
|
||||
notifyError(err, 'Branch failed')
|
||||
|
||||
return false
|
||||
}
|
||||
}, [activeSessionIdRef, busyRef, ensureSessionState, navigate, requestGateway, selectedStoredSessionIdRef, updateSessionState])
|
||||
},
|
||||
[
|
||||
activeSessionIdRef,
|
||||
busyRef,
|
||||
ensureSessionState,
|
||||
navigate,
|
||||
requestGateway,
|
||||
selectedStoredSessionIdRef,
|
||||
updateSessionState
|
||||
]
|
||||
)
|
||||
|
||||
const removeSession = useCallback(
|
||||
async (storedSessionId: string) => {
|
||||
|
||||
Reference in New Issue
Block a user