Date: Thu, 13 Aug 2026 21:06:51 -0600
Subject: [PATCH 061/141] refac
---
backend/open_webui/utils/middleware.py | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py
index 4f533b8eb7..9881d93d2a 100644
--- a/backend/open_webui/utils/middleware.py
+++ b/backend/open_webui/utils/middleware.py
@@ -2055,8 +2055,9 @@ def process_messages_with_output(
processed.extend(output_messages)
continue
- # Strip 'output' field before adding (LLM shouldn't see it)
- clean_message = {k: v for k, v in message.items() if k != 'output'}
+ clean_message = dict(message)
+ for key in ('id', 'files', 'output', 'contextSummary', 'context_summary', 'usage'):
+ clean_message.pop(key, None)
processed.append(clean_message)
return processed
@@ -2066,10 +2067,8 @@ def strip_compaction_fields(messages: list[dict]) -> list[dict]:
stripped = []
for message in messages:
clean = dict(message)
- clean.pop('contextSummary', None)
- clean.pop('context_summary', None)
- clean.pop('usage', None)
- clean.pop('id', None)
+ for key in ('id', 'files', 'output', 'contextSummary', 'context_summary', 'usage'):
+ clean.pop(key, None)
stripped.append(clean)
return stripped
From 653562d660398c32a9a193450bbbee300d7195c3 Mon Sep 17 00:00:00 2001
From: Timothy Jaeryang Baek
Date: Thu, 13 Aug 2026 21:15:26 -0600
Subject: [PATCH 062/141] refac
---
backend/open_webui/main.py | 2 ++
backend/open_webui/utils/middleware.py | 8 ++++----
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py
index 4a658bc264..9de07ad3e4 100644
--- a/backend/open_webui/main.py
+++ b/backend/open_webui/main.py
@@ -1547,6 +1547,8 @@ async def chat_completion(
for entry in message_ids:
target_model_id = entry['model_id']
assistant_message_id = entry['message_id']
+ if assistant_message_id and assistant_message_id == metadata.get('assistant_message_id'):
+ continue
if assistant_message_id:
assistant_message = {
'id': assistant_message_id,
diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py
index 9881d93d2a..213181275b 100644
--- a/backend/open_webui/utils/middleware.py
+++ b/backend/open_webui/utils/middleware.py
@@ -5165,7 +5165,7 @@ async def streaming_chat_response_handler(response, ctx):
await pause_for_tool_approval(
metadata['chat_id'],
metadata['message_id'],
- output,
+ full_output(),
form_data,
metadata,
)
@@ -5199,7 +5199,7 @@ async def streaming_chat_response_handler(response, ctx):
await pause_for_tool_approval(
metadata['chat_id'],
metadata['message_id'],
- output,
+ full_output(),
form_data,
metadata,
)
@@ -5478,7 +5478,7 @@ async def streaming_chat_response_handler(response, ctx):
# output sent to the frontend — they're only for LLM consumption
# via convert_output_to_messages.
frontend_output = []
- for item in output:
+ for item in full_output():
if item.get('type') == 'function_call_output':
parts = item.get('output', [])
if any(p.get('type') == 'input_image' for p in parts):
@@ -5564,7 +5564,7 @@ async def streaming_chat_response_handler(response, ctx):
# keeps indices aligned. The display prefix
# ensures the UI shows tool history during
# streaming.
- prior_output = list(output)
+ prior_output = list(full_output())
# Trim the trailing empty placeholder message
# so it doesn't persist as a ghost item once
# the new stream produces real content.
From b4738d1a2e6af1ce20adb322fc6d2aa2c9407901 Mon Sep 17 00:00:00 2001
From: Timothy Jaeryang Baek
Date: Thu, 13 Aug 2026 21:31:49 -0600
Subject: [PATCH 063/141] refac
---
src/lib/components/chat/ModelSelector/Selector.svelte | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/lib/components/chat/ModelSelector/Selector.svelte b/src/lib/components/chat/ModelSelector/Selector.svelte
index 2628a3bb5b..5492b90cd5 100644
--- a/src/lib/components/chat/ModelSelector/Selector.svelte
+++ b/src/lib/components/chat/ModelSelector/Selector.svelte
@@ -778,6 +778,11 @@
};
const setProviderDownloadConnections = async () => {
+ if ($user?.role !== 'admin') {
+ providerDownloadConnections = [];
+ return;
+ }
+
const openaiConfig = await getOpenAIConfig(localStorage.token).catch(() => null);
providerDownloadConnections =
openaiConfig?.ENABLE_OPENAI_API
From fa94a5ab2431edba064150651a14dd4992ef29e8 Mon Sep 17 00:00:00 2001
From: Timothy Jaeryang Baek
Date: Thu, 13 Aug 2026 21:36:41 -0600
Subject: [PATCH 064/141] refac
---
backend/open_webui/main.py | 50 ++++++++++--
backend/open_webui/utils/middleware.py | 48 ++++++++----
backend/open_webui/utils/misc.py | 101 ++++++++++++++-----------
3 files changed, 132 insertions(+), 67 deletions(-)
diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py
index 9de07ad3e4..e1978d7cfb 100644
--- a/backend/open_webui/main.py
+++ b/backend/open_webui/main.py
@@ -1851,14 +1851,6 @@ async def resolve_chat_message_tool_call(
db: AsyncSession = Depends(get_async_session),
):
resolution = await resolve_tool_call_output(id, message_id, form_data, user, db=db)
- if form_data.action != 'approve' and resolution['paused']:
- return {
- 'status': True,
- 'chat_id': id,
- 'message_id': message_id,
- 'paused': True,
- }
-
payload = await build_tool_approval_resume_payload(id, message_id, chat=resolution['chat'])
result = await chat_completion(request, payload, user)
return {
@@ -2119,6 +2111,7 @@ async def list_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=De
@app.post('/api/tasks/chat/{chat_id:path}/stop')
async def stop_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=Depends(get_verified_user)):
socket_id = get_temporary_chat_session_id(chat_id)
+ chat = None
if socket_id:
owner_id = get_user_id_from_session_pool(socket_id)
if owner_id != user.id and user.role != 'admin':
@@ -2128,6 +2121,47 @@ async def stop_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=De
if chat is None or (chat.user_id != user.id and user.role != 'admin'):
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND)
result = await stop_item_tasks(request.app.state.redis, chat_id)
+
+ if not socket_id and str(result.get('message', '')).startswith('No tasks found'):
+ messages_map = await Chats.get_messages_map_by_chat_id(chat_id) or {}
+ for message_id, message in messages_map.items():
+ if message.get('role') != 'assistant' or message.get('done') is not False:
+ continue
+
+ output = message.get('output')
+ if isinstance(output, list):
+ for item in output:
+ if item.get('type') == 'function_call' and item.get('status') in {
+ 'pending',
+ 'queued',
+ 'requires_approval',
+ }:
+ item['status'] = 'rejected'
+ item.pop('approved', None)
+
+ await Chats.upsert_message_to_chat_by_id_and_message_id(
+ chat_id,
+ message_id,
+ {'done': True, **({'output': output} if isinstance(output, list) else {})},
+ touch=False,
+ )
+ result = {
+ 'status': True,
+ 'message': 'Finalized pending approval message.',
+ }
+
+ event_emitter = await get_event_emitter(
+ {
+ 'user_id': chat.user_id,
+ 'chat_id': chat_id,
+ 'message_id': message_id,
+ },
+ update_db=False,
+ )
+ if event_emitter:
+ await event_emitter({'type': 'chat:completion', 'data': {'done': True, 'output': output}})
+ await event_emitter({'type': 'chat:tasks:cancel'})
+
return result
diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py
index 213181275b..4ccf1823f5 100644
--- a/backend/open_webui/utils/middleware.py
+++ b/backend/open_webui/utils/middleware.py
@@ -2063,16 +2063,6 @@ def process_messages_with_output(
return processed
-def strip_compaction_fields(messages: list[dict]) -> list[dict]:
- stripped = []
- for message in messages:
- clean = dict(message)
- for key in ('id', 'files', 'output', 'contextSummary', 'context_summary', 'usage'):
- clean.pop(key, None)
- stripped.append(clean)
- return stripped
-
-
def sanitize_tool_pairs(messages: list[dict]) -> list[dict]:
tool_result_ids = {
message.get('tool_call_id')
@@ -2331,8 +2321,6 @@ async def process_chat_payload(request, form_data, user, metadata, model):
except Exception:
log.exception('Context compaction failed; continuing with full chat history')
- form_data['messages'] = strip_compaction_fields(form_data.get('messages', []))
-
# Process messages with OR-aligned output items for clean LLM messages
form_data['messages'] = process_messages_with_output(
form_data.get('messages', []),
@@ -3109,6 +3097,20 @@ async def drain_approved_tool_calls(request, form_data, user, model, metadata) -
and item.get('call_id') not in result_call_ids
]
if not approved_calls:
+ if metadata.get('params', {}).get('tool_approval_mode', 'full') == 'ask' and any(
+ item.get('type') == 'function_call'
+ and item.get('name') != 'ask_user'
+ and (item.get('call_id') or item.get('id'))
+ and item.get('status') == 'queued'
+ and item.get('approved') is not True
+ and (item.get('call_id') or item.get('id')) not in result_call_ids
+ for item in output
+ ):
+ event_emitter, _ = await get_event_emitter_and_caller(metadata)
+ await pause_for_tool_approval(chat_id, message_id, output, form_data, metadata)
+ if event_emitter:
+ await event_emitter({'type': 'chat:completion', 'data': {'done': False, 'output': output}})
+ return True
return False
event_emitter, event_caller = await get_event_emitter_and_caller(metadata)
@@ -3146,6 +3148,21 @@ async def drain_approved_tool_calls(request, form_data, user, model, metadata) -
result_call_ids = {
item.get('call_id') for item in output if item.get('type') == 'function_call_output' and item.get('call_id')
}
+ if metadata.get('params', {}).get('tool_approval_mode', 'full') == 'ask' and any(
+ item.get('type') == 'function_call'
+ and item.get('name') != 'ask_user'
+ and (item.get('call_id') or item.get('id'))
+ and item.get('status') == 'queued'
+ and item.get('approved') is not True
+ and (item.get('call_id') or item.get('id')) not in result_call_ids
+ for item in output
+ ):
+ await pause_for_tool_approval(chat_id, message_id, output, form_data, metadata)
+ result_call_ids = {
+ item.get('call_id')
+ for item in output
+ if item.get('type') == 'function_call_output' and item.get('call_id')
+ }
paused = any(
item.get('type') == 'function_call'
and item.get('call_id')
@@ -3207,6 +3224,7 @@ async def pause_for_tool_approval(chat_id: str, message_id: str, output: list[di
result_call_ids = {
item.get('call_id') for item in output if item.get('type') == 'function_call_output' and item.get('call_id')
}
+ has_pending_approval = False
for item in output:
if item.get('type') == 'function_call' and not item.get('call_id') and item.get('id'):
item['call_id'] = item['id']
@@ -3217,7 +3235,11 @@ async def pause_for_tool_approval(chat_id: str, message_id: str, output: list[di
and item.get('call_id') not in result_call_ids
and item.get('status') != 'rejected'
):
- item['status'] = 'pending'
+ if not has_pending_approval:
+ item['status'] = 'pending'
+ has_pending_approval = True
+ elif item.get('status') == 'in_progress':
+ item['status'] = 'queued'
await Chats.upsert_message_to_chat_by_id_and_message_id(
chat_id,
diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py
index ce79102005..003db10bcf 100644
--- a/backend/open_webui/utils/misc.py
+++ b/backend/open_webui/utils/misc.py
@@ -293,6 +293,7 @@ def convert_output_to_messages(
pending_reasoning = [] # Only populated when reasoning_format == 'reasoning_content'
pending_reasoning_details = []
pending_tool_image_urls = []
+ pending_tool_outputs = []
completed_call_ids = {
item.get('call_id')
for item in output
@@ -347,9 +348,60 @@ def convert_output_to_messages(
)
pending_tool_image_urls = []
+ def flush_tool_outputs():
+ nonlocal pending_tool_outputs
+ if not pending_tool_outputs:
+ return
+
+ flush_pending()
+ for output_item in pending_tool_outputs:
+ output_parts = output_item.get('output', [])
+ content = ''
+ image_urls = []
+ for part in output_parts:
+ if part.get('type') == 'input_text':
+ output_text = part.get('text', '')
+ content += str(output_text) if not isinstance(output_text, str) else output_text
+ elif part.get('type') == 'input_image':
+ url = part.get('image_url', '')
+ if url:
+ image_urls.append(url)
+
+ if flatten_tool_images:
+ messages.append(
+ {
+ 'role': 'tool',
+ 'tool_call_id': output_item.get('call_id', ''),
+ 'content': content,
+ }
+ )
+ pending_tool_image_urls.extend(image_urls)
+ elif image_urls:
+ messages.append(
+ {
+ 'role': 'tool',
+ 'tool_call_id': output_item.get('call_id', ''),
+ 'content': [
+ {'type': 'input_text', 'text': content},
+ *[{'type': 'input_image', 'image_url': url} for url in image_urls],
+ ],
+ }
+ )
+ else:
+ messages.append(
+ {
+ 'role': 'tool',
+ 'tool_call_id': output_item.get('call_id', ''),
+ 'content': content,
+ }
+ )
+
+ pending_tool_outputs = []
+
for item in output:
item_type = item.get('type', '')
- if item_type != 'function_call_output':
+ if item_type not in {'function_call', 'function_call_output'}:
+ flush_tool_outputs()
flush_tool_images()
if item_type == 'message':
@@ -386,51 +438,7 @@ def convert_output_to_messages(
if item.get('call_id') not in function_call_ids:
continue
- # Flush any pending content/tool_calls before adding tool result
- flush_pending()
-
- # Extract text and images from output content parts
- output_parts = item.get('output', [])
- content = ''
- image_urls = []
- for part in output_parts:
- if part.get('type') == 'input_text':
- output_text = part.get('text', '')
- content += str(output_text) if not isinstance(output_text, str) else output_text
- elif part.get('type') == 'input_image':
- url = part.get('image_url', '')
- if url:
- image_urls.append(url)
-
- if flatten_tool_images:
- messages.append(
- {
- 'role': 'tool',
- 'tool_call_id': item.get('call_id', ''),
- 'content': content,
- }
- )
- if item.get('call_id') in function_call_ids:
- pending_tool_image_urls.extend(image_urls)
- elif image_urls:
- messages.append(
- {
- 'role': 'tool',
- 'tool_call_id': item.get('call_id', ''),
- 'content': [
- {'type': 'input_text', 'text': content},
- *[{'type': 'input_image', 'image_url': url} for url in image_urls],
- ],
- }
- )
- else:
- messages.append(
- {
- 'role': 'tool',
- 'tool_call_id': item.get('call_id', ''),
- 'content': content,
- }
- )
+ pending_tool_outputs.append(item)
elif item_type == 'reasoning':
reasoning_details = item.get('reasoning_details') if raw else None
@@ -484,6 +492,7 @@ def convert_output_to_messages(
pass
# Flush remaining content/tool_calls
+ flush_tool_outputs()
flush_tool_images()
flush_pending()
From 55c202e841e76cd69679206cd0ecb4a65b039ea4 Mon Sep 17 00:00:00 2001
From: Timothy Jaeryang Baek
Date: Thu, 13 Aug 2026 21:48:01 -0600
Subject: [PATCH 065/141] refac
---
src/lib/components/chat/Chat.svelte | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte
index 2c08b4a1b4..9fb1bd148e 100644
--- a/src/lib/components/chat/Chat.svelte
+++ b/src/lib/components/chat/Chat.svelte
@@ -83,7 +83,12 @@
} from '$lib/apis/chats';
import { generateOpenAIChatCompletion } from '$lib/apis/openai';
import { processUrl, processWebSearch } from '$lib/apis/retrieval';
- import { getAndUpdateUserLocation, getUserInfoById, getUserSettings } from '$lib/apis/users';
+ import {
+ getAndUpdateUserLocation,
+ getUserInfoById,
+ getUserSettings,
+ updateUserSettings
+ } from '$lib/apis/users';
import {
generateQueries,
chatAction,
@@ -415,13 +420,28 @@
let loadedChatIdProp = '';
let currentDraftKey = '';
- $: toolApprovalMode = params?.tool_approval_mode === 'ask' ? 'ask' : 'full';
+ $: toolApprovalMode =
+ (params?.tool_approval_mode ?? $settings?.params?.tool_approval_mode) === 'ask'
+ ? 'ask'
+ : 'full';
- const handleToolApprovalModeChange = (mode) => {
+ const handleToolApprovalModeChange = async (mode) => {
+ const tool_approval_mode = mode === 'ask' ? 'ask' : 'full';
params = {
...params,
- tool_approval_mode: mode === 'ask' ? 'ask' : 'full'
+ tool_approval_mode
};
+
+ settings.set({
+ ...$settings,
+ params: {
+ ...($settings?.params ?? {}),
+ tool_approval_mode
+ }
+ });
+ await updateUserSettings(localStorage.token, { ui: $settings }).catch((err) => {
+ console.error('[tool permissions settings]', err);
+ });
};
const parseToolArguments = (args) => {
From 256cce505be8ddd4930e8cb2536faea718d3f789 Mon Sep 17 00:00:00 2001
From: Timothy Jaeryang Baek
Date: Thu, 13 Aug 2026 21:51:04 -0600
Subject: [PATCH 066/141] refac
---
src/lib/components/chat/AskUserCard.svelte | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/lib/components/chat/AskUserCard.svelte b/src/lib/components/chat/AskUserCard.svelte
index 81a581fb66..bdd937ea48 100644
--- a/src/lib/components/chat/AskUserCard.svelte
+++ b/src/lib/components/chat/AskUserCard.svelte
@@ -3,6 +3,7 @@
import { onDestroy } from 'svelte';
import type { Writable } from 'svelte/store';
import type { i18n as i18nType } from 'i18next';
+ import Tooltip from '$lib/components/common/Tooltip.svelte';
const i18n: Writable = getContext('i18n');
const dispatch = createEventDispatcher();
@@ -207,11 +208,18 @@
on:click={() => selectOption(question, option, optionIndex)}
>
{option.label}
-
- {option.description}
-
+
+ {option.description}
+
+
{#if optionIndex === 0}
Date: Thu, 13 Aug 2026 22:01:15 -0600
Subject: [PATCH 067/141] refac
---
src/lib/components/chat/Chat.svelte | 19 +++++++++++++------
src/lib/components/chat/Messages.svelte | 2 ++
.../chat/Messages/ContentRenderer.svelte | 4 ++++
.../Messages/Markdown/MarkdownTokens.svelte | 13 ++++++++-----
.../components/chat/Messages/Message.svelte | 3 +++
.../Messages/MultiResponseMessages.svelte | 3 +++
.../chat/Messages/ResponseMessage.svelte | 2 ++
.../Messages/StructuredOutputRenderer.svelte | 15 ++++++++++-----
8 files changed, 45 insertions(+), 16 deletions(-)
diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte
index 9fb1bd148e..7edb0b5a7e 100644
--- a/src/lib/components/chat/Chat.svelte
+++ b/src/lib/components/chat/Chat.svelte
@@ -502,13 +502,14 @@
return;
}
- await resolveChatMessageToolCall(localStorage.token, $chatId, messageId, callId, 'answer', {
+ const res = await resolveChatMessageToolCall(localStorage.token, $chatId, messageId, callId, 'answer', {
answers,
timed_out: timedOut
}).catch(async (error) => {
toast.error(`${error}`);
await loadChat();
});
+ onToolCallResolved(res);
};
const rejectPendingAskUser = async (messageId, callId) => {
@@ -516,7 +517,7 @@
return;
}
- await resolveChatMessageToolCall(
+ const res = await resolveChatMessageToolCall(
localStorage.token,
$chatId,
messageId,
@@ -526,6 +527,7 @@
toast.error(`${error}`);
await loadChat();
});
+ onToolCallResolved(res);
};
$: pendingAskUser = findPendingAskUser(history);
@@ -658,6 +660,13 @@
}
};
+ const onToolCallResolved = (res) => {
+ const newTaskIds = res?.task_ids ?? (res?.task_id ? [res.task_id] : []);
+ if (newTaskIds.length > 0) {
+ taskIds = [...(taskIds ?? []), ...newTaskIds];
+ }
+ };
+
let oldSelectedModelIds = [''];
$: if (!equal(selectedModelIds, oldSelectedModelIds)) {
onSelectedModelIdsChange();
@@ -3568,10 +3577,7 @@
await handleOpenAIError(res.error, responseMessage);
} else {
// Backend returns task_ids (multi-model) or task_id (single model)
- const newTaskIds = res.task_ids ?? (res.task_id ? [res.task_id] : []);
- if (newTaskIds.length > 0) {
- taskIds = [...(taskIds ?? []), ...newTaskIds];
- }
+ onToolCallResolved(res);
// Backend returns chat_id for new chats — set store + URL.
// Only update if the user hasn't navigated to a different chat
@@ -4287,6 +4293,7 @@
{mergeResponses}
{chatActionHandler}
{addMessages}
+ {onToolCallResolved}
allowDelete={!(generating || taskIds?.length)}
forkHandler={handleForkChat}
topPadding={!embedded}
diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte
index 2f4ad5fec9..301aa93c6b 100644
--- a/src/lib/components/chat/Messages.svelte
+++ b/src/lib/components/chat/Messages.svelte
@@ -40,6 +40,7 @@
export let showMessage: Function = () => {};
export let submitMessage: Function = () => {};
export let addMessages: Function = () => {};
+ export let onToolCallResolved: Function = () => {};
export let forkHandler: Function | null = null;
export let readOnly = false;
@@ -555,6 +556,7 @@
{continueResponse}
{mergeResponses}
{addMessages}
+ {onToolCallResolved}
{forkHandler}
{allowDelete}
{triggerScroll}
diff --git a/src/lib/components/chat/Messages/ContentRenderer.svelte b/src/lib/components/chat/Messages/ContentRenderer.svelte
index 340a43b00b..36e9fc6ae4 100644
--- a/src/lib/components/chat/Messages/ContentRenderer.svelte
+++ b/src/lib/components/chat/Messages/ContentRenderer.svelte
@@ -93,6 +93,7 @@
export let onSave = (e) => {};
export let onSourceClick = (e) => {};
export let onTaskClick = (e) => {};
+ export let onToolCallResolved = (e) => {};
export let onSetInputText = (text) => {};
let contentContainerElement;
@@ -299,6 +300,7 @@
{formatMessageContent}
{onSourceClick}
{onTaskClick}
+ {onToolCallResolved}
{onSave}
onUpdate={markdownUpdateHandler}
onPreview={previewHandler}
@@ -320,6 +322,7 @@
{sourceIds}
{onSourceClick}
{onTaskClick}
+ {onToolCallResolved}
{onSave}
onUpdate={markdownUpdateHandler}
onPreview={previewHandler}
@@ -340,6 +343,7 @@
{preview}
{compactPreview}
{done}
+ {onToolCallResolved}
/>
{/if}
diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte
index 94410eab80..5f0f36babc 100644
--- a/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte
+++ b/src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte
@@ -54,6 +54,7 @@
export let onTaskClick: Function = () => {};
export let onSourceClick: Function = () => {};
+ export let onToolCallResolved: Function = () => {};
const headerComponent = (depth: number) => {
return 'h' + depth;
@@ -111,13 +112,14 @@
resolvingCallId = callId;
try {
- await resolveChatMessageToolCall(
+ const res = await resolveChatMessageToolCall(
localStorage.token,
chatId,
messageId,
callId,
approved ? 'approve' : 'reject'
);
+ onToolCallResolved(res);
} catch (err) {
toast.error(String(err));
} finally {
@@ -314,10 +316,11 @@
{preview}
{compactPreview}
{editCodeBlock}
- {onTaskClick}
- {sourceIds}
- {onSourceClick}
- />
+ {onTaskClick}
+ {sourceIds}
+ {onSourceClick}
+ {onToolCallResolved}
+ />
{/if}
{:else if token.type === 'list'}
diff --git a/src/lib/components/chat/Messages/Message.svelte b/src/lib/components/chat/Messages/Message.svelte
index c899c9dccd..9d1bb0672c 100644
--- a/src/lib/components/chat/Messages/Message.svelte
+++ b/src/lib/components/chat/Messages/Message.svelte
@@ -39,6 +39,7 @@
export let mergeResponses;
export let addMessages;
+ export let onToolCallResolved: Function = () => {};
export let forkHandler: Function | null = null;
export let triggerScroll;
export let readOnly = false;
@@ -107,6 +108,7 @@
{continueResponse}
{regenerateResponse}
{addMessages}
+ {onToolCallResolved}
{forkHandler}
{readOnly}
{compactPreview}
@@ -135,6 +137,7 @@
{mergeResponses}
{triggerScroll}
{addMessages}
+ {onToolCallResolved}
{forkHandler}
{readOnly}
{compactPreview}
diff --git a/src/lib/components/chat/Messages/MultiResponseMessages.svelte b/src/lib/components/chat/Messages/MultiResponseMessages.svelte
index c52a6de388..d01ba315af 100644
--- a/src/lib/components/chat/Messages/MultiResponseMessages.svelte
+++ b/src/lib/components/chat/Messages/MultiResponseMessages.svelte
@@ -48,6 +48,7 @@
export let mergeResponses: Function;
export let addMessages: Function;
+ export let onToolCallResolved: Function = () => {};
export let forkHandler: Function | null = null;
export let triggerScroll: Function;
@@ -328,6 +329,7 @@
groupedMessageIds[selectedModelIdx].messageIds.length - 1;
}}
{addMessages}
+ {onToolCallResolved}
{forkHandler}
{readOnly}
{compactPreview}
@@ -391,6 +393,7 @@
groupedMessageIds[modelIdx].messageIds.length - 1;
}}
{addMessages}
+ {onToolCallResolved}
{forkHandler}
{readOnly}
{compactPreview}
diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte
index 9a2963ca68..a493a42a5b 100644
--- a/src/lib/components/chat/Messages/ResponseMessage.svelte
+++ b/src/lib/components/chat/Messages/ResponseMessage.svelte
@@ -160,6 +160,7 @@
export let forkHandler: Function | null = null;
export let addMessages: Function;
+ export let onToolCallResolved: Function = () => {};
export let isLastMessage = true;
export let readOnly = false;
@@ -835,6 +836,7 @@
onTaskClick={async (e) => {
console.log(e);
}}
+ {onToolCallResolved}
onSourceClick={async (id) => {
console.log(id);
diff --git a/src/lib/components/chat/Messages/StructuredOutputRenderer.svelte b/src/lib/components/chat/Messages/StructuredOutputRenderer.svelte
index ac85562d7a..434cd34a68 100644
--- a/src/lib/components/chat/Messages/StructuredOutputRenderer.svelte
+++ b/src/lib/components/chat/Messages/StructuredOutputRenderer.svelte
@@ -33,6 +33,7 @@
export let onTaskClick: any = () => {};
export let onUpdate: any = () => {};
export let onPreview: any = () => {};
+ export let onToolCallResolved: any = () => {};
const getDetailTitle = (detailToken: OutputDetailToken): any => detailToken.summary;
const getDetailAttributes = (detailToken: OutputDetailToken): any => detailToken.attributes;
@@ -45,13 +46,14 @@
resolvingCallId = callId;
try {
- await resolveChatMessageToolCall(
+ const res = await resolveChatMessageToolCall(
localStorage.token,
chatId,
messageId,
callId,
approved ? 'approve' : 'reject'
);
+ onToolCallResolved(res);
} catch (err) {
toast.error(String(err));
} finally {
@@ -85,6 +87,7 @@
{sourceIds}
{onSourceClick}
{onTaskClick}
+ {onToolCallResolved}
{onSave}
{onUpdate}
{onPreview}
@@ -139,6 +142,7 @@
{preview}
{compactPreview}
{editCodeBlock}
+ {onToolCallResolved}
/>