From b0c9a166121464cf264f45f5977b896aa54391e3 Mon Sep 17 00:00:00 2001 From: nl_0 Date: Fri, 29 Nov 2024 12:23:36 +0100 Subject: [PATCH] better error handling --- .../app/components/Assistant/Model/Bedrock.ts | 42 ++++++++++++------- .../Assistant/Model/Conversation.ts | 10 ++--- catalog/app/components/Assistant/Model/LLM.ts | 10 ++++- .../app/components/Assistant/UI/Chat/Chat.tsx | 5 ++- 4 files changed, 44 insertions(+), 23 deletions(-) diff --git a/catalog/app/components/Assistant/Model/Bedrock.ts b/catalog/app/components/Assistant/Model/Bedrock.ts index 54a644e90bd..0bd21d24cce 100644 --- a/catalog/app/components/Assistant/Model/Bedrock.ts +++ b/catalog/app/components/Assistant/Model/Bedrock.ts @@ -1,3 +1,4 @@ +import type * as AWSSDK from 'aws-sdk' import BedrockRuntime from 'aws-sdk/clients/bedrockruntime' import * as Eff from 'effect' @@ -114,6 +115,10 @@ const toolConfigToBedrock = ( }), }) +function isAWSError(e: any): e is AWSSDK.AWSError { + return e.code !== undefined && e.message !== undefined +} + // a layer providing the service over aws.bedrock export function LLMBedrock(bedrock: BedrockRuntime) { const converse = (prompt: LLM.Prompt, opts?: LLM.Options) => @@ -131,21 +136,28 @@ export function LLMBedrock(bedrock: BedrockRuntime) { opts, ], })( - Eff.Effect.tryPromise(() => - bedrock - .converse({ - modelId: getModelId(), - system: [{ text: prompt.system }], - messages: messagesToBedrock(prompt.messages), - toolConfig: prompt.toolConfig && toolConfigToBedrock(prompt.toolConfig), - ...opts, - }) - .promise() - .then((backendResponse) => ({ - backendResponse, - content: mapContent(backendResponse.output.message?.content), - })), - ), + Eff.Effect.tryPromise({ + try: () => + bedrock + .converse({ + modelId: getModelId(), + system: [{ text: prompt.system }], + messages: messagesToBedrock(prompt.messages), + toolConfig: prompt.toolConfig && toolConfigToBedrock(prompt.toolConfig), + ...opts, + }) + .promise() + .then((backendResponse) => ({ + backendResponse, + content: mapContent(backendResponse.output.message?.content), + })), + catch: (e) => + new LLM.LLMError({ + message: isAWSError(e) + ? `Bedrock error (${e.code}): ${e.message}` + : `Unexpected error: ${e}`, + }), + }), ) return Eff.Layer.succeed(LLM.LLM, { converse }) diff --git a/catalog/app/components/Assistant/Model/Conversation.ts b/catalog/app/components/Assistant/Model/Conversation.ts index 5fcbb1ef578..50a7ee8053e 100644 --- a/catalog/app/components/Assistant/Model/Conversation.ts +++ b/catalog/app/components/Assistant/Model/Conversation.ts @@ -98,7 +98,7 @@ export type Action = Eff.Data.TaggedEnum<{ readonly content: string } LLMError: { - readonly error: Eff.Cause.UnknownException + readonly error: LLM.LLMError } LLMResponse: { readonly content: Exclude[] @@ -144,8 +144,8 @@ const llmRequest = (events: Event[]) => const response = yield* llm.converse(prompt) if (Eff.Option.isNone(response.content)) { - return yield* new Eff.Cause.UnknownException( - new Error('No content in LLM response'), + return yield* Eff.Effect.fail( + new LLM.LLMError({ message: 'No content in LLM response' }), ) } @@ -193,8 +193,8 @@ export const ConversationActor = Eff.Effect.succeed( WaitingForAssistant: { LLMError: ({ events }, { error }) => idle(events, { - message: 'Error while interacting with LLM. Please try again.', - details: `${error}`, + message: 'Error while interacting with LLM.', + details: error.message, }), LLMResponse: (state, { content, toolUses }, dispatch) => Eff.Effect.gen(function* () { diff --git a/catalog/app/components/Assistant/Model/LLM.ts b/catalog/app/components/Assistant/Model/LLM.ts index be093502fc8..98be8ad3b26 100644 --- a/catalog/app/components/Assistant/Model/LLM.ts +++ b/catalog/app/components/Assistant/Model/LLM.ts @@ -57,6 +57,14 @@ interface ConverseResponse { backendResponse: BedrockRuntime.ConverseResponse } +export class LLMError { + message: string + + constructor({ message }: { message: string }) { + this.message = message + } +} + // a service export class LLM extends Eff.Context.Tag('LLM')< LLM, @@ -64,6 +72,6 @@ export class LLM extends Eff.Context.Tag('LLM')< converse: ( prompt: Prompt, opts?: Options, - ) => Eff.Effect.Effect + ) => Eff.Effect.Effect } >() {} diff --git a/catalog/app/components/Assistant/UI/Chat/Chat.tsx b/catalog/app/components/Assistant/UI/Chat/Chat.tsx index 82578e0c6de..0b58b93acc6 100644 --- a/catalog/app/components/Assistant/UI/Chat/Chat.tsx +++ b/catalog/app/components/Assistant/UI/Chat/Chat.tsx @@ -465,8 +465,9 @@ export default function Chat({ state, dispatch }: ChatProps) { Eff.Option.match(s.error, { onSome: (e) => ( - Error occurred: {e.message} -
{e.details}
+ {e.message} +
+ {e.details}
// TODO: retry / discard ),