Spaces:
Paused
Paused
Add error message for tools (#1163)
Browse files* feat: add error message for tools
* lint
---------
Co-authored-by: Nathan Sarrazin <sarrazin.nathan@gmail.com>
src/lib/components/OpenWebSearchResults.svelte
CHANGED
|
@@ -16,7 +16,10 @@
|
|
| 16 |
$: lastMessage = webSearchMessages
|
| 17 |
.filter((update) => update.subtype !== MessageWebSearchUpdateType.Sources)
|
| 18 |
.at(-1) as MessageWebSearchUpdate;
|
| 19 |
-
$:
|
|
|
|
|
|
|
|
|
|
| 20 |
</script>
|
| 21 |
|
| 22 |
<details
|
|
|
|
| 16 |
$: lastMessage = webSearchMessages
|
| 17 |
.filter((update) => update.subtype !== MessageWebSearchUpdateType.Sources)
|
| 18 |
.at(-1) as MessageWebSearchUpdate;
|
| 19 |
+
$: errored = webSearchMessages.some(
|
| 20 |
+
(update) => update.subtype === MessageWebSearchUpdateType.Error
|
| 21 |
+
);
|
| 22 |
+
$: loading = !sources && !errored;
|
| 23 |
</script>
|
| 24 |
|
| 25 |
<details
|
src/lib/components/chat/ChatMessage.svelte
CHANGED
|
@@ -29,7 +29,11 @@
|
|
| 29 |
type MessageWebSearchSourcesUpdate,
|
| 30 |
type MessageWebSearchUpdate,
|
| 31 |
} from "$lib/types/MessageUpdate";
|
| 32 |
-
import {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
import type { ToolFront } from "$lib/types/Tool";
|
| 34 |
import { base } from "$app/paths";
|
| 35 |
import { useConvTreeStore } from "$lib/stores/convTree";
|
|
@@ -287,6 +291,7 @@
|
|
| 287 |
{#each Object.values(toolUpdates) as tool}
|
| 288 |
{#if tool.length}
|
| 289 |
{@const toolName = tool.find(isMessageToolCallUpdate)?.call.name}
|
|
|
|
| 290 |
{@const toolDone = tool.some(isMessageToolResultUpdate)}
|
| 291 |
{#if toolName && toolName !== "websearch"}
|
| 292 |
<details
|
|
@@ -301,7 +306,7 @@
|
|
| 301 |
>
|
| 302 |
<svg
|
| 303 |
class="absolute inset-0 text-purple-500/40 transition-opacity"
|
| 304 |
-
class:invisible={toolDone}
|
| 305 |
width="22"
|
| 306 |
height="22"
|
| 307 |
viewBox="0 0 38 38"
|
|
@@ -321,7 +326,7 @@
|
|
| 321 |
</div>
|
| 322 |
|
| 323 |
<span>
|
| 324 |
-
{toolDone ? "Called" : "Calling"} tool
|
| 325 |
<span class="font-semibold"
|
| 326 |
>{availableTools.find((el) => toolHasName(toolName, el))?.displayName}</span
|
| 327 |
>
|
|
@@ -341,6 +346,12 @@
|
|
| 341 |
</li>
|
| 342 |
{/each}
|
| 343 |
</ul>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 344 |
{/if}
|
| 345 |
{/each}
|
| 346 |
</details>
|
|
|
|
| 29 |
type MessageWebSearchSourcesUpdate,
|
| 30 |
type MessageWebSearchUpdate,
|
| 31 |
} from "$lib/types/MessageUpdate";
|
| 32 |
+
import {
|
| 33 |
+
isMessageToolCallUpdate,
|
| 34 |
+
isMessageToolResultUpdate,
|
| 35 |
+
isMessageToolErrorUpdate,
|
| 36 |
+
} from "$lib/utils/messageUpdates";
|
| 37 |
import type { ToolFront } from "$lib/types/Tool";
|
| 38 |
import { base } from "$app/paths";
|
| 39 |
import { useConvTreeStore } from "$lib/stores/convTree";
|
|
|
|
| 291 |
{#each Object.values(toolUpdates) as tool}
|
| 292 |
{#if tool.length}
|
| 293 |
{@const toolName = tool.find(isMessageToolCallUpdate)?.call.name}
|
| 294 |
+
{@const toolError = tool.some(isMessageToolErrorUpdate)}
|
| 295 |
{@const toolDone = tool.some(isMessageToolResultUpdate)}
|
| 296 |
{#if toolName && toolName !== "websearch"}
|
| 297 |
<details
|
|
|
|
| 306 |
>
|
| 307 |
<svg
|
| 308 |
class="absolute inset-0 text-purple-500/40 transition-opacity"
|
| 309 |
+
class:invisible={toolDone || toolError}
|
| 310 |
width="22"
|
| 311 |
height="22"
|
| 312 |
viewBox="0 0 38 38"
|
|
|
|
| 326 |
</div>
|
| 327 |
|
| 328 |
<span>
|
| 329 |
+
{toolError ? "Error calling" : toolDone ? "Called" : "Calling"} tool
|
| 330 |
<span class="font-semibold"
|
| 331 |
>{availableTools.find((el) => toolHasName(toolName, el))?.displayName}</span
|
| 332 |
>
|
|
|
|
| 346 |
</li>
|
| 347 |
{/each}
|
| 348 |
</ul>
|
| 349 |
+
{:else if toolUpdate.subtype === MessageToolUpdateType.Error}
|
| 350 |
+
<div class="mt-1 flex items-center gap-2 opacity-80">
|
| 351 |
+
<h3 class="text-sm">Error</h3>
|
| 352 |
+
<div class="h-px flex-1 bg-gradient-to-r from-gray-500/20" />
|
| 353 |
+
</div>
|
| 354 |
+
<p class="text-sm">{toolUpdate.message}</p>
|
| 355 |
{/if}
|
| 356 |
{/each}
|
| 357 |
</details>
|
src/lib/server/textGeneration/tools.ts
CHANGED
|
@@ -69,19 +69,38 @@ async function* runTool(
|
|
| 69 |
call,
|
| 70 |
};
|
| 71 |
try {
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
} catch (cause) {
|
| 86 |
console.error(Error(`Failed while running tool ${call.name}`), { cause });
|
| 87 |
return {
|
|
|
|
| 69 |
call,
|
| 70 |
};
|
| 71 |
try {
|
| 72 |
+
try {
|
| 73 |
+
const toolResult = yield* tool.call(call.parameters, {
|
| 74 |
+
conv,
|
| 75 |
+
messages,
|
| 76 |
+
preprompt,
|
| 77 |
+
assistant,
|
| 78 |
+
});
|
| 79 |
+
if (toolResult.status === ToolResultStatus.Error) {
|
| 80 |
+
yield {
|
| 81 |
+
type: MessageUpdateType.Tool,
|
| 82 |
+
subtype: MessageToolUpdateType.Error,
|
| 83 |
+
uuid,
|
| 84 |
+
message: toolResult.message,
|
| 85 |
+
};
|
| 86 |
+
} else {
|
| 87 |
+
yield {
|
| 88 |
+
type: MessageUpdateType.Tool,
|
| 89 |
+
subtype: MessageToolUpdateType.Result,
|
| 90 |
+
uuid,
|
| 91 |
+
result: { ...toolResult, call } as ToolResult,
|
| 92 |
+
};
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
return { ...toolResult, call } as ToolResult;
|
| 96 |
+
} catch (e) {
|
| 97 |
+
yield {
|
| 98 |
+
type: MessageUpdateType.Tool,
|
| 99 |
+
subtype: MessageToolUpdateType.Error,
|
| 100 |
+
uuid,
|
| 101 |
+
message: e instanceof Error ? e.message : String(e),
|
| 102 |
+
};
|
| 103 |
+
}
|
| 104 |
} catch (cause) {
|
| 105 |
console.error(Error(`Failed while running tool ${call.name}`), { cause });
|
| 106 |
return {
|
src/lib/server/tools/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Assistant } from "$lib/types/Assistant";
|
|
| 2 |
import type { Conversation } from "$lib/types/Conversation";
|
| 3 |
import type { Message } from "$lib/types/Message";
|
| 4 |
import type { MessageUpdate } from "$lib/types/MessageUpdate";
|
| 5 |
-
import type { Tool,
|
| 6 |
|
| 7 |
import calculator from "./calculator";
|
| 8 |
import directlyAnswer from "./directlyAnswer";
|
|
@@ -19,11 +19,17 @@ export interface BackendToolContext {
|
|
| 19 |
assistant?: Pick<Assistant, "rag" | "dynamicPrompt" | "generateSettings">;
|
| 20 |
}
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
export interface BackendTool extends Tool {
|
| 23 |
call(
|
| 24 |
params: Record<string, string | number | boolean>,
|
| 25 |
context: BackendToolContext
|
| 26 |
-
): AsyncGenerator<MessageUpdate,
|
| 27 |
}
|
| 28 |
|
| 29 |
export const allTools: BackendTool[] = [
|
|
|
|
| 2 |
import type { Conversation } from "$lib/types/Conversation";
|
| 3 |
import type { Message } from "$lib/types/Message";
|
| 4 |
import type { MessageUpdate } from "$lib/types/MessageUpdate";
|
| 5 |
+
import type { Tool, ToolResultError, ToolResultSuccess } from "$lib/types/Tool";
|
| 6 |
|
| 7 |
import calculator from "./calculator";
|
| 8 |
import directlyAnswer from "./directlyAnswer";
|
|
|
|
| 19 |
assistant?: Pick<Assistant, "rag" | "dynamicPrompt" | "generateSettings">;
|
| 20 |
}
|
| 21 |
|
| 22 |
+
// typescript can't narrow a discriminated union after applying a generic like Omit to it
|
| 23 |
+
// so we have to define the omitted types and create a new union
|
| 24 |
+
type ToolResultSuccessOmitted = Omit<ToolResultSuccess, "call">;
|
| 25 |
+
type ToolResultErrorOmitted = Omit<ToolResultError, "call">;
|
| 26 |
+
type ToolResultOmitted = ToolResultSuccessOmitted | ToolResultErrorOmitted;
|
| 27 |
+
|
| 28 |
export interface BackendTool extends Tool {
|
| 29 |
call(
|
| 30 |
params: Record<string, string | number | boolean>,
|
| 31 |
context: BackendToolContext
|
| 32 |
+
): AsyncGenerator<MessageUpdate, ToolResultOmitted, undefined>;
|
| 33 |
}
|
| 34 |
|
| 35 |
export const allTools: BackendTool[] = [
|
src/lib/types/MessageUpdate.ts
CHANGED
|
@@ -74,6 +74,8 @@ export enum MessageToolUpdateType {
|
|
| 74 |
Call = "call",
|
| 75 |
/** The result of a tool call */
|
| 76 |
Result = "result",
|
|
|
|
|
|
|
| 77 |
}
|
| 78 |
interface MessageToolBaseUpdate<TSubType extends MessageToolUpdateType> {
|
| 79 |
type: MessageUpdateType.Tool;
|
|
@@ -87,7 +89,13 @@ export interface MessageToolResultUpdate
|
|
| 87 |
extends MessageToolBaseUpdate<MessageToolUpdateType.Result> {
|
| 88 |
result: ToolResult;
|
| 89 |
}
|
| 90 |
-
export
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
// Everything else
|
| 93 |
export interface MessageTitleUpdate {
|
|
|
|
| 74 |
Call = "call",
|
| 75 |
/** The result of a tool call */
|
| 76 |
Result = "result",
|
| 77 |
+
/** Error while running tool */
|
| 78 |
+
Error = "error",
|
| 79 |
}
|
| 80 |
interface MessageToolBaseUpdate<TSubType extends MessageToolUpdateType> {
|
| 81 |
type: MessageUpdateType.Tool;
|
|
|
|
| 89 |
extends MessageToolBaseUpdate<MessageToolUpdateType.Result> {
|
| 90 |
result: ToolResult;
|
| 91 |
}
|
| 92 |
+
export interface MessageToolErrorUpdate extends MessageToolBaseUpdate<MessageToolUpdateType.Error> {
|
| 93 |
+
message: string;
|
| 94 |
+
}
|
| 95 |
+
export type MessageToolUpdate =
|
| 96 |
+
| MessageToolCallUpdate
|
| 97 |
+
| MessageToolResultUpdate
|
| 98 |
+
| MessageToolErrorUpdate;
|
| 99 |
|
| 100 |
// Everything else
|
| 101 |
export interface MessageTitleUpdate {
|
src/lib/types/Tool.ts
CHANGED
|
@@ -31,13 +31,13 @@ export enum ToolResultStatus {
|
|
| 31 |
Success = "success",
|
| 32 |
Error = "error",
|
| 33 |
}
|
| 34 |
-
interface ToolResultSuccess {
|
| 35 |
status: ToolResultStatus.Success;
|
| 36 |
call: ToolCall;
|
| 37 |
outputs: Record<string, unknown>[];
|
| 38 |
display?: boolean;
|
| 39 |
}
|
| 40 |
-
interface ToolResultError {
|
| 41 |
status: ToolResultStatus.Error;
|
| 42 |
call: ToolCall;
|
| 43 |
message: string;
|
|
|
|
| 31 |
Success = "success",
|
| 32 |
Error = "error",
|
| 33 |
}
|
| 34 |
+
export interface ToolResultSuccess {
|
| 35 |
status: ToolResultStatus.Success;
|
| 36 |
call: ToolCall;
|
| 37 |
outputs: Record<string, unknown>[];
|
| 38 |
display?: boolean;
|
| 39 |
}
|
| 40 |
+
export interface ToolResultError {
|
| 41 |
status: ToolResultStatus.Error;
|
| 42 |
call: ToolCall;
|
| 43 |
message: string;
|
src/lib/utils/messageUpdates.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
| 11 |
type MessageWebSearchSourcesUpdate,
|
| 12 |
type MessageWebSearchErrorUpdate,
|
| 13 |
MessageWebSearchUpdateType,
|
|
|
|
|
|
|
| 14 |
} from "$lib/types/MessageUpdate";
|
| 15 |
|
| 16 |
export const isMessageWebSearchUpdate = (update: MessageUpdate): update is MessageWebSearchUpdate =>
|
|
@@ -32,8 +34,12 @@ export const isMessageToolUpdate = (update: MessageUpdate): update is MessageToo
|
|
| 32 |
update.type === MessageUpdateType.Tool;
|
| 33 |
export const isMessageToolCallUpdate = (update: MessageUpdate): update is MessageToolCallUpdate =>
|
| 34 |
isMessageToolUpdate(update) && update.subtype === MessageToolUpdateType.Call;
|
| 35 |
-
export const isMessageToolResultUpdate = (
|
|
|
|
|
|
|
| 36 |
isMessageToolUpdate(update) && update.subtype === MessageToolUpdateType.Result;
|
|
|
|
|
|
|
| 37 |
|
| 38 |
type MessageUpdateRequestOptions = {
|
| 39 |
base: string;
|
|
|
|
| 11 |
type MessageWebSearchSourcesUpdate,
|
| 12 |
type MessageWebSearchErrorUpdate,
|
| 13 |
MessageWebSearchUpdateType,
|
| 14 |
+
type MessageToolErrorUpdate,
|
| 15 |
+
type MessageToolResultUpdate,
|
| 16 |
} from "$lib/types/MessageUpdate";
|
| 17 |
|
| 18 |
export const isMessageWebSearchUpdate = (update: MessageUpdate): update is MessageWebSearchUpdate =>
|
|
|
|
| 34 |
update.type === MessageUpdateType.Tool;
|
| 35 |
export const isMessageToolCallUpdate = (update: MessageUpdate): update is MessageToolCallUpdate =>
|
| 36 |
isMessageToolUpdate(update) && update.subtype === MessageToolUpdateType.Call;
|
| 37 |
+
export const isMessageToolResultUpdate = (
|
| 38 |
+
update: MessageUpdate
|
| 39 |
+
): update is MessageToolResultUpdate =>
|
| 40 |
isMessageToolUpdate(update) && update.subtype === MessageToolUpdateType.Result;
|
| 41 |
+
export const isMessageToolErrorUpdate = (update: MessageUpdate): update is MessageToolErrorUpdate =>
|
| 42 |
+
isMessageToolUpdate(update) && update.subtype === MessageToolUpdateType.Error;
|
| 43 |
|
| 44 |
type MessageUpdateRequestOptions = {
|
| 45 |
base: string;
|