refac
This commit is contained in:
@@ -77,6 +77,7 @@
|
||||
getAllTags,
|
||||
getChatById,
|
||||
getTagsById,
|
||||
resolveChatMessageToolCall,
|
||||
updateChatById,
|
||||
updateChatFolderIdById
|
||||
} from '$lib/apis/chats';
|
||||
@@ -423,6 +424,131 @@
|
||||
};
|
||||
};
|
||||
|
||||
const parseToolArguments = (args) => {
|
||||
if (!args) {
|
||||
return {};
|
||||
}
|
||||
let value = args;
|
||||
while (typeof value === 'string') {
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : {};
|
||||
};
|
||||
|
||||
const getPendingAskUserFromMessage = (message) => {
|
||||
if (message?.role !== 'assistant' || !Array.isArray(message.output)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const call = message.output.find(
|
||||
(item) =>
|
||||
item?.type === 'function_call' &&
|
||||
item?.name === 'ask_user' &&
|
||||
item?.status === 'pending' &&
|
||||
(item?.call_id || item?.id)
|
||||
);
|
||||
|
||||
if (call) {
|
||||
return { message, call, args: parseToolArguments(call.arguments) };
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const findPendingAskUser = (chatHistory) => {
|
||||
if (!chatHistory?.messages) {
|
||||
return null;
|
||||
}
|
||||
const messages = chatHistory.currentId
|
||||
? createMessagesList(chatHistory, chatHistory.currentId)
|
||||
: Object.values(chatHistory.messages);
|
||||
for (const message of [...messages].reverse()) {
|
||||
const pending = getPendingAskUserFromMessage(message);
|
||||
if (pending) return pending;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const messageHasPendingAskUser = (message) => {
|
||||
return !!getPendingAskUserFromMessage(message);
|
||||
};
|
||||
|
||||
const answerPendingAskUser = async (messageId, callId, answers, timedOut = false) => {
|
||||
if (!$chatId || !messageId || !callId) {
|
||||
return;
|
||||
}
|
||||
|
||||
await resolveChatMessageToolCall(localStorage.token, $chatId, messageId, callId, 'answer', {
|
||||
answers,
|
||||
timed_out: timedOut
|
||||
}).catch(async (error) => {
|
||||
toast.error(`${error}`);
|
||||
await loadChat();
|
||||
});
|
||||
};
|
||||
|
||||
const rejectPendingAskUser = async (messageId, callId) => {
|
||||
if (!$chatId || !messageId || !callId) {
|
||||
return;
|
||||
}
|
||||
|
||||
await resolveChatMessageToolCall(
|
||||
localStorage.token,
|
||||
$chatId,
|
||||
messageId,
|
||||
callId,
|
||||
'reject'
|
||||
).catch(async (error) => {
|
||||
toast.error(`${error}`);
|
||||
await loadChat();
|
||||
});
|
||||
};
|
||||
|
||||
$: pendingAskUser = findPendingAskUser(history);
|
||||
$: savedAskUserPrompt = pendingAskUser
|
||||
? {
|
||||
show: true,
|
||||
questions: Array.isArray(pendingAskUser.args?.questions)
|
||||
? pendingAskUser.args.questions
|
||||
: [],
|
||||
allowOther: pendingAskUser.args?.allow_other !== false,
|
||||
timeoutMs: null,
|
||||
onConfirm: (value) => {
|
||||
void answerPendingAskUser(
|
||||
pendingAskUser.message.id,
|
||||
pendingAskUser.call.call_id || pendingAskUser.call.id,
|
||||
value?.answers ?? {},
|
||||
false
|
||||
);
|
||||
},
|
||||
onCancel: () => {
|
||||
void rejectPendingAskUser(
|
||||
pendingAskUser.message.id,
|
||||
pendingAskUser.call.call_id || pendingAskUser.call.id
|
||||
);
|
||||
}
|
||||
}
|
||||
: null;
|
||||
|
||||
$: socketAskUserPrompt = {
|
||||
show: showAskUserDialog,
|
||||
questions: askUserQuestions,
|
||||
allowOther: askUserAllowOther,
|
||||
timeoutMs: askUserTimeoutMs,
|
||||
onConfirm: (value) => {
|
||||
showAskUserDialog = false;
|
||||
eventCallback(value);
|
||||
},
|
||||
onCancel: () => {
|
||||
showAskUserDialog = false;
|
||||
eventCallback({ status: 'cancelled', answers: {} });
|
||||
}
|
||||
};
|
||||
|
||||
const mergeChatVariableSchemas = (modelIds = [], availableModels = []) => {
|
||||
const byKey: Record<string, any> = {};
|
||||
const conflicts: any[] = [];
|
||||
@@ -2175,7 +2301,11 @@
|
||||
} else {
|
||||
taskIds = null;
|
||||
// No active tasks and message incomplete → generation was interrupted
|
||||
if (currentMessage?.role === 'assistant' && !currentMessage.done) {
|
||||
if (
|
||||
currentMessage?.role === 'assistant' &&
|
||||
!currentMessage.done &&
|
||||
!messageHasPendingAskUser(currentMessage)
|
||||
) {
|
||||
currentMessage.done = true;
|
||||
}
|
||||
}
|
||||
@@ -2586,6 +2716,7 @@
|
||||
}
|
||||
|
||||
history.messages[message.id] = message;
|
||||
history = history;
|
||||
|
||||
if (done) {
|
||||
message.done = true;
|
||||
@@ -4192,20 +4323,7 @@
|
||||
{onUpdate}
|
||||
messageQueue={$chatRequestQueues[$chatId] ?? []}
|
||||
{chatTasks}
|
||||
askUser={{
|
||||
show: showAskUserDialog,
|
||||
questions: askUserQuestions,
|
||||
allowOther: askUserAllowOther,
|
||||
timeoutMs: askUserTimeoutMs,
|
||||
onConfirm: (value) => {
|
||||
showAskUserDialog = false;
|
||||
eventCallback(value);
|
||||
},
|
||||
onCancel: () => {
|
||||
showAskUserDialog = false;
|
||||
eventCallback({ status: 'cancelled', answers: {} });
|
||||
}
|
||||
}}
|
||||
askUser={savedAskUserPrompt ?? socketAskUserPrompt}
|
||||
onQueueSendNow={sendQueuedMessageNow}
|
||||
onQueueEdit={editQueuedMessage}
|
||||
onQueueDelete={deleteQueuedMessage}
|
||||
@@ -4296,20 +4414,7 @@
|
||||
{onUpdate}
|
||||
messageQueue={$chatRequestQueues[$chatId] ?? []}
|
||||
{chatTasks}
|
||||
askUser={{
|
||||
show: showAskUserDialog,
|
||||
questions: askUserQuestions,
|
||||
allowOther: askUserAllowOther,
|
||||
timeoutMs: askUserTimeoutMs,
|
||||
onConfirm: (value) => {
|
||||
showAskUserDialog = false;
|
||||
eventCallback(value);
|
||||
},
|
||||
onCancel: () => {
|
||||
showAskUserDialog = false;
|
||||
eventCallback({ status: 'cancelled', answers: {} });
|
||||
}
|
||||
}}
|
||||
askUser={savedAskUserPrompt ?? socketAskUserPrompt}
|
||||
onQueueSendNow={sendQueuedMessageNow}
|
||||
onQueueEdit={editQueuedMessage}
|
||||
onQueueDelete={deleteQueuedMessage}
|
||||
@@ -4354,6 +4459,7 @@
|
||||
{onUpload}
|
||||
{onUpdate}
|
||||
messageQueue={$chatRequestQueues[$chatId] ?? []}
|
||||
askUser={savedAskUserPrompt ?? socketAskUserPrompt}
|
||||
onQueueSendNow={sendQueuedMessageNow}
|
||||
onQueueEdit={editQueuedMessage}
|
||||
onQueueDelete={deleteQueuedMessage}
|
||||
|
||||
@@ -153,11 +153,20 @@
|
||||
|
||||
export let history;
|
||||
export let taskIds = null;
|
||||
export let askUser: AskUserPrompt = {
|
||||
show: false,
|
||||
questions: [],
|
||||
allowOther: true,
|
||||
timeoutMs: null,
|
||||
onConfirm: (_value: any) => {},
|
||||
onCancel: () => {}
|
||||
};
|
||||
|
||||
$: isActive =
|
||||
(taskIds && taskIds.length > 0) ||
|
||||
(history.currentId && history.messages[history.currentId]?.done != true) ||
|
||||
generating;
|
||||
!askUser?.show &&
|
||||
((taskIds && taskIds.length > 0) ||
|
||||
(history.currentId && history.messages[history.currentId]?.done != true) ||
|
||||
generating);
|
||||
$: canCompact = !!history?.currentId;
|
||||
|
||||
export let prompt = '';
|
||||
@@ -182,15 +191,6 @@
|
||||
export let onQueueEdit: (id: string) => void = () => {};
|
||||
export let onQueueDelete: (id: string) => void = () => {};
|
||||
export let onUpdate: (data?: { file?: any }) => void = () => {};
|
||||
export let askUser: AskUserPrompt = {
|
||||
show: false,
|
||||
questions: [],
|
||||
allowOther: true,
|
||||
timeoutMs: null,
|
||||
onConfirm: (_value: any) => {},
|
||||
onCancel: () => {}
|
||||
};
|
||||
|
||||
export let chatTasks = [];
|
||||
|
||||
let inputContent = null;
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if resolvable && pendingToolTokens.length === 1}
|
||||
{#if resolvable && pendingToolTokens.length === 1 && pendingToolTokens[0]?.attributes?.name !== 'ask_user'}
|
||||
{@const pendingCallId = pendingToolTokens[0]?.attributes?.id ?? ''}
|
||||
<span class="flex gap-1 shrink-0">
|
||||
<button
|
||||
@@ -210,24 +210,26 @@
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400 flex-1 min-w-0 line-clamp-1">
|
||||
{token?.attributes?.name ?? $i18n.t('tool')}
|
||||
</span>
|
||||
<span class="flex gap-1 shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
class="text-[0.6875rem] px-2.5 py-0.5 rounded-md text-gray-600 dark:text-gray-300 bg-gray-100 dark:bg-white/8 hover:bg-gray-200 dark:hover:bg-white/12 transition-colors duration-100 disabled:opacity-50"
|
||||
disabled={!pendingCallId || resolvingCallId === pendingCallId}
|
||||
on:click={() => onResolve(pendingCallId, true)}
|
||||
>
|
||||
{$i18n.t('Allow')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="text-[0.6875rem] px-2 py-0.5 rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300 transition-colors duration-100 disabled:opacity-50"
|
||||
disabled={!pendingCallId || resolvingCallId === pendingCallId}
|
||||
on:click={() => onResolve(pendingCallId, false)}
|
||||
>
|
||||
{$i18n.t('Deny')}
|
||||
</button>
|
||||
</span>
|
||||
{#if token?.attributes?.name !== 'ask_user'}
|
||||
<span class="flex gap-1 shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
class="text-[0.6875rem] px-2.5 py-0.5 rounded-md text-gray-600 dark:text-gray-300 bg-gray-100 dark:bg-white/8 hover:bg-gray-200 dark:hover:bg-white/12 transition-colors duration-100 disabled:opacity-50"
|
||||
disabled={!pendingCallId || resolvingCallId === pendingCallId}
|
||||
on:click={() => onResolve(pendingCallId, true)}
|
||||
>
|
||||
{$i18n.t('Allow')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="text-[0.6875rem] px-2 py-0.5 rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300 transition-colors duration-100 disabled:opacity-50"
|
||||
disabled={!pendingCallId || resolvingCallId === pendingCallId}
|
||||
on:click={() => onResolve(pendingCallId, false)}
|
||||
>
|
||||
{$i18n.t('Deny')}
|
||||
</button>
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -145,7 +145,8 @@ function buildToolCallToken(item: OutputItem, toolOutputByCallId: Record<string,
|
||||
}
|
||||
|
||||
return {
|
||||
summary: status === 'pending' ? 'Tool Approval Needed' : isDone ? 'Tool Executed' : 'Executing...',
|
||||
summary:
|
||||
status === 'pending' ? 'Tool Approval Needed' : isDone ? 'Tool Executed' : 'Executing...',
|
||||
text: getToolResultText(resultItem),
|
||||
attributes: {
|
||||
type: 'tool_calls',
|
||||
@@ -299,6 +300,14 @@ export function buildOutputDisplayItems(output: OutputItem[] = []): OutputDispla
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
item?.type === 'function_call' &&
|
||||
item.name === 'ask_user' &&
|
||||
(item.status === 'pending' || item.status === 'in_progress')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item?.type && GROUPABLE_OUTPUT_TYPES.has(item.type)) {
|
||||
const token = buildDetailToken(item, index === output.length - 1, toolOutputByCallId);
|
||||
if (token) {
|
||||
|
||||
@@ -66,7 +66,14 @@
|
||||
export let onQueueSendNow: (id: string) => void = () => {};
|
||||
export let onQueueEdit: (id: string) => void = () => {};
|
||||
export let onQueueDelete: (id: string) => void = () => {};
|
||||
|
||||
export let askUser = {
|
||||
show: false,
|
||||
questions: [],
|
||||
allowOther: true,
|
||||
timeoutMs: null,
|
||||
onConfirm: (_value: any) => {},
|
||||
onCancel: () => {}
|
||||
};
|
||||
|
||||
export let dragged = false;
|
||||
|
||||
@@ -251,6 +258,7 @@
|
||||
{onQueueSendNow}
|
||||
{onQueueEdit}
|
||||
{onQueueDelete}
|
||||
{askUser}
|
||||
{onWebSearchToggle}
|
||||
on:chatVariables
|
||||
on:submit={(e) => {
|
||||
|
||||
Reference in New Issue
Block a user