From 2a145e278cca60794931ff4bb2342749cb786932 Mon Sep 17 00:00:00 2001 From: elijahbenizzy Date: Mon, 16 Sep 2024 22:24:24 -0700 Subject: [PATCH] WIP --- burr/core/action.py | 72 +++++-- burr/tracking/server/run.py | 2 + telemetry/ui/src/api/index.ts | 7 +- telemetry/ui/src/api/models/AppResponse.ts | 10 + .../ui/src/api/models/ClarificationAnswers.ts | 7 + .../src/api/models/ClarificationQuestions.ts | 7 + telemetry/ui/src/api/models/Email.ts | 8 + ...assistant__server__EmailAssistantState.ts} | 6 +- ...stapi__application__EmailAssistantState.ts | 18 ++ .../ui/src/api/services/DefaultService.ts | 183 +++++++++++++++++- telemetry/ui/src/examples/EmailAssistant.tsx | 77 ++++---- 11 files changed, 332 insertions(+), 65 deletions(-) create mode 100644 telemetry/ui/src/api/models/AppResponse.ts create mode 100644 telemetry/ui/src/api/models/ClarificationAnswers.ts create mode 100644 telemetry/ui/src/api/models/ClarificationQuestions.ts create mode 100644 telemetry/ui/src/api/models/Email.ts rename telemetry/ui/src/api/models/{EmailAssistantState.ts => burr__examples__email_assistant__server__EmailAssistantState.ts} (69%) create mode 100644 telemetry/ui/src/api/models/examples__fastapi__application__EmailAssistantState.ts diff --git a/burr/core/action.py b/burr/core/action.py index cb9a7ac5..9d248c41 100644 --- a/burr/core/action.py +++ b/burr/core/action.py @@ -70,17 +70,40 @@ def run(self, state: State, **run_kwargs) -> dict: pass @property - def inputs(self) -> Union[list[str], tuple[list[str], list[str]]]: + def inputs( + self, + ) -> Tuple[Union[list[str], Dict[str, Type[Type]]], Union[list[str], Dict[str, Type[Type]]]]: """Represents inputs that are used for this to run. These correspond to the ``**run_kwargs`` in `run` above. Note that this has two possible return values: - 1. A list of strings -- these are the keys that are required to run the function - 2. A tuple of two lists of strings -- the first list is the required keys, the second is the optional keys + 1. A list of strings/dict of string -> ypes -- these are the keys that are required to run the function + 2. A tuple of two lists of strings/dict of strings -> types -- the first list is the required keys, the second is the optional keys :return: Either a list of strings (required inputs) or a tuple of two lists of strings (required and optional inputs) """ - return [] + return [], [] + + @property + def input_schema(self) -> Tuple[dict[str, Type[Type]], dict[str, Type[Type]]]: + """Returns the input schema for the function. + The input schema is a type that can be used to validate the input to the function. + + Note that this is separate from inputs() for backwards compatibility -- + inputs() can return a schema *or* a tuple of required and optional inputs. + + :return: Tuple of required inputs and optional inputs with attached types + """ + inputs = self.inputs + if len(inputs) == 1: + inputs = (inputs[0], {}) + out = [] + for input_spec in inputs: + if isinstance(input_spec, list): + out.append({key: Any for key in input_spec}) + else: + out.append(input_spec) + return tuple(out) @property def optional_and_required_inputs(self) -> tuple[set[str], set[str]]: @@ -213,11 +236,6 @@ def get_source(self) -> str: to display a different source""" return inspect.getsource(self.__class__) - def input_schema(self) -> Any: - """Returns the input schema for the action. - The input schema is a type that can be used to validate the input to the action""" - return None - def __repr__(self): read_repr = ", ".join(self.reads) if self.reads else "{}" write_repr = ", ".join(self.writes) if self.writes else "{}" @@ -534,7 +552,9 @@ def is_async(self) -> bool: # the following exist to share implementation between FunctionBasedStreamingAction and FunctionBasedAction # TODO -- think through the class hierarchy to simplify, for now this is OK -def derive_inputs_from_fn(bound_params: dict, fn: Callable) -> tuple[list[str], list[str]]: +def derive_inputs_from_fn( + bound_params: dict, fn: Callable +) -> tuple[dict[str, Type[Type]], dict[str, Type[Type]]]: """Derives inputs from the function, given the bound parameters. This assumes that the function has inputs named `state`, as well as any number of other kwarg-boundable parameters. @@ -543,20 +563,30 @@ def derive_inputs_from_fn(bound_params: dict, fn: Callable) -> tuple[list[str], :return: Required and optional inputs """ sig = inspect.signature(fn) - required_inputs, optional_inputs = [], [] + required_inputs, optional_inputs = {}, {} for param_name, param in sig.parameters.items(): if param_name != "state" and param_name not in bound_params: if param.default is inspect.Parameter.empty: # has no default means its required - required_inputs.append(param_name) + required_inputs[param_name] = ( + param.annotation if param.annotation != inspect.Parameter.empty else Any + ) else: # has a default means its optional - optional_inputs.append(param_name) + optional_inputs[param_name] = ( + param.annotation if param.annotation != inspect.Parameter.empty else Any + ) return required_inputs, optional_inputs FunctionBasedActionType = Union["FunctionBasedAction", "FunctionBasedStreamingAction"] +InputSpec = [ + Tuple[Union[list[str], Dict[str, Type[Type]], Union[list[str], Dict[str, Type[Type]]]]] +] + +OptionalInputType = Optional[InputSpec] + class FunctionBasedAction(SingleStepAction): ACTION_FUNCTION = "action_function" @@ -567,7 +597,9 @@ def __init__( reads: List[str], writes: List[str], bound_params: Optional[dict] = None, - input_spec: Optional[tuple[list[str], list[str]]] = None, + input_spec: Optional[ + Tuple[Union[list[str], Dict[str, Type[Type]]], Union[list[str], Dict[str, Type[Type]]]] + ] = None, originating_fn: Optional[Callable] = None, schema: ActionSchema = DEFAULT_SCHEMA, ): @@ -609,7 +641,9 @@ def writes(self) -> list[str]: return self._writes @property - def inputs(self) -> tuple[list[str], list[str]]: + def inputs( + self, + ) -> Tuple[Union[list[str], Dict[str, Type[Type]]], Union[list[str], Dict[str, Type[Type]]]]: return self._inputs @property @@ -1044,7 +1078,9 @@ def __init__( reads: List[str], writes: List[str], bound_params: Optional[dict] = None, - input_spec: Optional[tuple[list[str], list[str]]] = None, + input_spec: Optional[ + Tuple[Union[list[str], Dict[str, Type[Type]]], Union[list[str], Dict[str, Type[Type]]]] + ] = None, originating_fn: Optional[Callable] = None, schema: ActionSchema = DEFAULT_SCHEMA, ): @@ -1117,7 +1153,9 @@ def with_params(self, **kwargs: Any) -> "FunctionBasedStreamingAction": ) @property - def inputs(self) -> tuple[list[str], list[str]]: + def inputs( + self, + ) -> Tuple[Union[list[str], Dict[str, Type[Type]]], Union[list[str], Dict[str, Type[Type]]]]: return self._inputs @property diff --git a/burr/tracking/server/run.py b/burr/tracking/server/run.py index f99c4602..8ddffad5 100644 --- a/burr/tracking/server/run.py +++ b/burr/tracking/server/run.py @@ -32,6 +32,7 @@ # dynamic importing due to the dashes (which make reading the examples on github easier) email_assistant = importlib.import_module("burr.examples.email-assistant.server") + email_assistant_typed = importlib.import_module("burr.examples.fastapi.server") chatbot = importlib.import_module("burr.examples.multi-modal-chatbot.server") streaming_chatbot = importlib.import_module("burr.examples.streaming-fastapi.server") @@ -249,6 +250,7 @@ async def version() -> dict: # Examples -- todo -- put them behind `if` statements app.include_router(chatbot.router, prefix="/api/v0/chatbot") app.include_router(email_assistant.router, prefix="/api/v0/email_assistant") +app.include_router(email_assistant_typed.router, prefix="/api/v0/email_assistant_typed") app.include_router(streaming_chatbot.router, prefix="/api/v0/streaming_chatbot") if SERVE_STATIC: diff --git a/telemetry/ui/src/api/index.ts b/telemetry/ui/src/api/index.ts index 35b03467..e8967da0 100644 --- a/telemetry/ui/src/api/index.ts +++ b/telemetry/ui/src/api/index.ts @@ -12,17 +12,22 @@ export type { ApplicationLogs } from './models/ApplicationLogs'; export type { ApplicationModel } from './models/ApplicationModel'; export type { ApplicationPage } from './models/ApplicationPage'; export type { ApplicationSummary } from './models/ApplicationSummary'; +export type { AppResponse } from './models/AppResponse'; export type { AttributeModel } from './models/AttributeModel'; export type { BackendSpec } from './models/BackendSpec'; export type { BeginEntryModel } from './models/BeginEntryModel'; export type { BeginSpanModel } from './models/BeginSpanModel'; +export { burr__examples__email_assistant__server__EmailAssistantState } from './models/burr__examples__email_assistant__server__EmailAssistantState'; export { ChatItem } from './models/ChatItem'; export { ChildApplicationModel } from './models/ChildApplicationModel'; +export type { ClarificationAnswers } from './models/ClarificationAnswers'; +export type { ClarificationQuestions } from './models/ClarificationQuestions'; export type { DraftInit } from './models/DraftInit'; -export { EmailAssistantState } from './models/EmailAssistantState'; +export type { Email } from './models/Email'; export type { EndEntryModel } from './models/EndEntryModel'; export type { EndSpanModel } from './models/EndSpanModel'; export type { EndStreamModel } from './models/EndStreamModel'; +export type { examples__fastapi__application__EmailAssistantState } from './models/examples__fastapi__application__EmailAssistantState'; export type { Feedback } from './models/Feedback'; export type { FirstItemStreamModel } from './models/FirstItemStreamModel'; export type { HTTPValidationError } from './models/HTTPValidationError'; diff --git a/telemetry/ui/src/api/models/AppResponse.ts b/telemetry/ui/src/api/models/AppResponse.ts new file mode 100644 index 00000000..e526c9f6 --- /dev/null +++ b/telemetry/ui/src/api/models/AppResponse.ts @@ -0,0 +1,10 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { examples__fastapi__application__EmailAssistantState } from './examples__fastapi__application__EmailAssistantState'; +export type AppResponse = { + app_id: string; + next_step: 'process_input' | 'clarify_instructions' | 'process_feedback' | null; + state: examples__fastapi__application__EmailAssistantState; +}; diff --git a/telemetry/ui/src/api/models/ClarificationAnswers.ts b/telemetry/ui/src/api/models/ClarificationAnswers.ts new file mode 100644 index 00000000..98bdd15a --- /dev/null +++ b/telemetry/ui/src/api/models/ClarificationAnswers.ts @@ -0,0 +1,7 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type ClarificationAnswers = { + answers: Array; +}; diff --git a/telemetry/ui/src/api/models/ClarificationQuestions.ts b/telemetry/ui/src/api/models/ClarificationQuestions.ts new file mode 100644 index 00000000..8ce3afbe --- /dev/null +++ b/telemetry/ui/src/api/models/ClarificationQuestions.ts @@ -0,0 +1,7 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type ClarificationQuestions = { + question: Array; +}; diff --git a/telemetry/ui/src/api/models/Email.ts b/telemetry/ui/src/api/models/Email.ts new file mode 100644 index 00000000..7e050b8c --- /dev/null +++ b/telemetry/ui/src/api/models/Email.ts @@ -0,0 +1,8 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type Email = { + subject: string; + contents: string; +}; diff --git a/telemetry/ui/src/api/models/EmailAssistantState.ts b/telemetry/ui/src/api/models/burr__examples__email_assistant__server__EmailAssistantState.ts similarity index 69% rename from telemetry/ui/src/api/models/EmailAssistantState.ts rename to telemetry/ui/src/api/models/burr__examples__email_assistant__server__EmailAssistantState.ts index 4a2ed93b..233ff84a 100644 --- a/telemetry/ui/src/api/models/EmailAssistantState.ts +++ b/telemetry/ui/src/api/models/burr__examples__email_assistant__server__EmailAssistantState.ts @@ -2,7 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -export type EmailAssistantState = { +export type burr__examples__email_assistant__server__EmailAssistantState = { app_id: string; email_to_respond: string | null; response_instructions: string | null; @@ -11,9 +11,9 @@ export type EmailAssistantState = { drafts: Array; feedback_history: Array; final_draft: string | null; - next_step: EmailAssistantState.next_step; + next_step: burr__examples__email_assistant__server__EmailAssistantState.next_step; }; -export namespace EmailAssistantState { +export namespace burr__examples__email_assistant__server__EmailAssistantState { export enum next_step { PROCESS_INPUT = 'process_input', CLARIFY_INSTRUCTIONS = 'clarify_instructions', diff --git a/telemetry/ui/src/api/models/examples__fastapi__application__EmailAssistantState.ts b/telemetry/ui/src/api/models/examples__fastapi__application__EmailAssistantState.ts new file mode 100644 index 00000000..518ad1d9 --- /dev/null +++ b/telemetry/ui/src/api/models/examples__fastapi__application__EmailAssistantState.ts @@ -0,0 +1,18 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { ClarificationAnswers } from './ClarificationAnswers'; +import type { ClarificationQuestions } from './ClarificationQuestions'; +import type { Email } from './Email'; +export type examples__fastapi__application__EmailAssistantState = { + email_to_respond?: string | null; + response_instructions?: string | null; + questions?: ClarificationQuestions | null; + answers?: ClarificationAnswers | null; + draft_history?: Array; + current_draft?: Email | null; + feedback_history?: Array; + feedback?: string | null; + final_draft?: string | null; +}; diff --git a/telemetry/ui/src/api/services/DefaultService.ts b/telemetry/ui/src/api/services/DefaultService.ts index 2d4ff459..6ee309c8 100644 --- a/telemetry/ui/src/api/services/DefaultService.ts +++ b/telemetry/ui/src/api/services/DefaultService.ts @@ -4,10 +4,11 @@ /* eslint-disable */ import type { ApplicationLogs } from '../models/ApplicationLogs'; import type { ApplicationPage } from '../models/ApplicationPage'; +import type { AppResponse } from '../models/AppResponse'; import type { BackendSpec } from '../models/BackendSpec'; +import type { burr__examples__email_assistant__server__EmailAssistantState } from '../models/burr__examples__email_assistant__server__EmailAssistantState'; import type { ChatItem } from '../models/ChatItem'; import type { DraftInit } from '../models/DraftInit'; -import type { EmailAssistantState } from '../models/EmailAssistantState'; import type { Feedback } from '../models/Feedback'; import type { IndexingJob } from '../models/IndexingJob'; import type { Project } from '../models/Project'; @@ -297,14 +298,14 @@ export class DefaultService { * @param projectId * @param appId * @param requestBody - * @returns EmailAssistantState Successful Response + * @returns burr__examples__email_assistant__server__EmailAssistantState Successful Response * @throws ApiError */ public static initializeDraftApiV0EmailAssistantCreateProjectIdAppIdPost( projectId: string, appId: string, requestBody: DraftInit - ): CancelablePromise { + ): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/api/v0/email_assistant/create/{project_id}/{app_id}', @@ -330,14 +331,14 @@ export class DefaultService { * @param projectId * @param appId * @param requestBody - * @returns EmailAssistantState Successful Response + * @returns burr__examples__email_assistant__server__EmailAssistantState Successful Response * @throws ApiError */ public static answerQuestionsApiV0EmailAssistantAnswerQuestionsProjectIdAppIdPost( projectId: string, appId: string, requestBody: QuestionAnswers - ): CancelablePromise { + ): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/api/v0/email_assistant/answer_questions/{project_id}/{app_id}', @@ -363,14 +364,14 @@ export class DefaultService { * @param projectId * @param appId * @param requestBody - * @returns EmailAssistantState Successful Response + * @returns burr__examples__email_assistant__server__EmailAssistantState Successful Response * @throws ApiError */ public static provideFeedbackApiV0EmailAssistantProvideFeedbackProjectIdAppIdPost( projectId: string, appId: string, requestBody: Feedback - ): CancelablePromise { + ): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/api/v0/email_assistant/provide_feedback/{project_id}/{app_id}', @@ -394,13 +395,13 @@ export class DefaultService { * :return: The state of the application * @param projectId * @param appId - * @returns EmailAssistantState Successful Response + * @returns burr__examples__email_assistant__server__EmailAssistantState Successful Response * @throws ApiError */ public static getStateApiV0EmailAssistantStateProjectIdAppIdGet( projectId: string, appId: string - ): CancelablePromise { + ): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/api/v0/email_assistant/state/{project_id}/{app_id}', @@ -427,6 +428,170 @@ export class DefaultService { url: '/api/v0/email_assistant/validate/{project_id}/{app_id}' }); } + /** + * Create New Application + * @param projectId + * @param appId + * @returns string Successful Response + * @throws ApiError + */ + public static createNewApplicationApiV0EmailAssistantTypedCreateNewProjectIdAppIdPost( + projectId: string, + appId: string + ): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v0/email_assistant_typed/create_new/{project_id}/{app_id}', + path: { + project_id: projectId, + app_id: appId + }, + errors: { + 422: `Validation Error` + } + }); + } + /** + * Initialize Draft + * Endpoint to initialize the draft with the email and instructions + * + * :param project_id: ID of the project (used by telemetry tracking/storage) + * :param app_id: ID of the application (used to reference the app) + * :param draft_data: Data to initialize the draft + * :return: The state of the application after initialization + * @param projectId + * @param appId + * @param requestBody + * @returns AppResponse Successful Response + * @throws ApiError + */ + public static initializeDraftApiV0EmailAssistantTypedCreateProjectIdAppIdPost( + projectId: string, + appId: string, + requestBody: DraftInit + ): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v0/email_assistant_typed/create/{project_id}/{app_id}', + path: { + project_id: projectId, + app_id: appId + }, + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error` + } + }); + } + /** + * Answer Questions + * Endpoint to answer questions the LLM provides + * + * :param project_id: ID of the project (used by telemetry tracking/storage) + * :param app_id: ID of the application (used to reference the app) + * :param question_answers: Answers to the questions + * :return: The state of the application after answering the questions + * @param projectId + * @param appId + * @param requestBody + * @returns AppResponse Successful Response + * @throws ApiError + */ + public static answerQuestionsApiV0EmailAssistantTypedAnswerQuestionsProjectIdAppIdPost( + projectId: string, + appId: string, + requestBody: QuestionAnswers + ): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v0/email_assistant_typed/answer_questions/{project_id}/{app_id}', + path: { + project_id: projectId, + app_id: appId + }, + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error` + } + }); + } + /** + * Provide Feedback + * Endpoint to provide feedback to the LLM + * + * :param project_id: ID of the project (used by telemetry tracking/storage) + * :param app_id: ID of the application (used to reference the app) + * :param feedback: Feedback to provide to the LLM + * :return: The state of the application after providing feedback + * @param projectId + * @param appId + * @param requestBody + * @returns AppResponse Successful Response + * @throws ApiError + */ + public static provideFeedbackApiV0EmailAssistantTypedProvideFeedbackProjectIdAppIdPost( + projectId: string, + appId: string, + requestBody: Feedback + ): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v0/email_assistant_typed/provide_feedback/{project_id}/{app_id}', + path: { + project_id: projectId, + app_id: appId + }, + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error` + } + }); + } + /** + * Get State + * Get the current state of the application + * + * :param project_id: ID of the project (used by telemetry tracking/storage) + * :param app_id: ID of the application (used to reference the app) + * :return: The state of the application + * @param projectId + * @param appId + * @returns AppResponse Successful Response + * @throws ApiError + */ + public static getStateApiV0EmailAssistantTypedStateProjectIdAppIdGet( + projectId: string, + appId: string + ): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v0/email_assistant_typed/state/{project_id}/{app_id}', + path: { + project_id: projectId, + app_id: appId + }, + errors: { + 422: `Validation Error` + } + }); + } + /** + * Validate Environment + * Validate the environment + * @returns any Successful Response + * @throws ApiError + */ + public static validateEnvironmentApiV0EmailAssistantTypedValidateProjectIdAppIdGet(): CancelablePromise< + string | null + > { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v0/email_assistant_typed/validate/{project_id}/{app_id}' + }); + } /** * Chat Response * Chat response endpoint. User passes in a prompt and the system returns the diff --git a/telemetry/ui/src/examples/EmailAssistant.tsx b/telemetry/ui/src/examples/EmailAssistant.tsx index 42f80fce..4029cda3 100644 --- a/telemetry/ui/src/examples/EmailAssistant.tsx +++ b/telemetry/ui/src/examples/EmailAssistant.tsx @@ -4,9 +4,11 @@ import { ApplicationSummary, DefaultService, DraftInit, - EmailAssistantState, + // examples__fastapi__application__EmailAssistantState as EmailAssistantState, + AppResponse, Feedback, - QuestionAnswers + QuestionAnswers, + Email } from '../api'; import { useEffect, useState } from 'react'; import { useMutation, useQuery } from 'react-query'; @@ -77,19 +79,20 @@ export const InitialDraftView = (props: { }; export const SubmitAnswersView = (props: { - state: EmailAssistantState; + state: AppResponse; submitAnswers: (questions: QuestionAnswers) => void; questions: string[] | null; answers: string[] | null; isLoading: boolean; }) => { - const questions = props.state.questions || []; + const questions = props.state.state.questions?.question || []; const [answers, setAnswers] = useState(props.answers || questions.map(() => '')); const editMode = props.isLoading || props.answers === null; + const { state } = props.state; return (
- {(props.state.questions || []).map((question, index) => { + {(state.questions?.question || []).map((question, index) => { return ( @@ -121,9 +124,9 @@ export const SubmitAnswersView = (props: { }; export const SubmitFeedbackView = (props: { - state: EmailAssistantState; + state: AppResponse; submitFeedback: (feedbacks: Feedback) => void; - drafts: string[] | null; + drafts: Email[] | null; feedbacks: string[] | null; isLoading: boolean; }) => { @@ -141,7 +144,7 @@ export const SubmitFeedbackView = (props: { <>
-                  {draft}
+                  {draft.subject + '\n' + draft.contents || ''}
                 

@@ -185,18 +188,21 @@ export const SubmitFeedbackView = (props: { export const EmailAssistant = (props: { projectId: string; appId: string | undefined }) => { // starts off as null - const [emailAssistantState, setEmailAssistantState] = useState(null); + const [appResponse, setAppResponse] = useState(null); const { data: validationData, isLoading: isValidationLoading } = useQuery( ['valid', props.projectId, props.appId], - DefaultService.validateEnvironmentApiV0EmailAssistantValidateProjectIdAppIdGet + DefaultService.validateEnvironmentApiV0EmailAssistantTypedValidateProjectIdAppIdGet ); useEffect(() => { if (props.appId !== undefined) { // TODO -- handle errors - DefaultService.getStateApiV0EmailAssistantStateProjectIdAppIdGet(props.projectId, props.appId) + DefaultService.getStateApiV0EmailAssistantTypedStateProjectIdAppIdGet( + props.projectId, + props.appId + ) .then((data) => { - setEmailAssistantState(data); // we want to initialize the chat history + setAppResponse(data); // we want to initialize the chat history }) .catch((e) => { // eslint-disable-next-line @@ -209,7 +215,7 @@ export const EmailAssistant = (props: { projectId: string; appId: string | undef // TODO -- handle errors ['emailAssistant', props.projectId, props.appId], () => - DefaultService.getStateApiV0EmailAssistantStateProjectIdAppIdGet( + DefaultService.getStateApiV0EmailAssistantTypedStateProjectIdAppIdGet( props.projectId, props.appId || '' // TODO -- find a cleaner way of doing a skip-token like thing here // This is skipped if the appId is undefined so this is just to make the type-checker happy @@ -217,48 +223,48 @@ export const EmailAssistant = (props: { projectId: string; appId: string | undef { enabled: props.appId !== undefined, onSuccess: (data) => { - setEmailAssistantState(data); // when its succesful we want to set the displayed chat history + setAppResponse(data); // when its succesful we want to set the displayed chat history } } ); const submitInitialMutation = useMutation( (draftData: DraftInit) => - DefaultService.initializeDraftApiV0EmailAssistantCreateProjectIdAppIdPost( + DefaultService.initializeDraftApiV0EmailAssistantTypedCreateProjectIdAppIdPost( props.projectId, props.appId || 'create_new', draftData ), { onSuccess: (data) => { - setEmailAssistantState(data); + setAppResponse(data); } } ); const submitAnswersMutation = useMutation( (answers: QuestionAnswers) => - DefaultService.answerQuestionsApiV0EmailAssistantAnswerQuestionsProjectIdAppIdPost( + DefaultService.answerQuestionsApiV0EmailAssistantTypedAnswerQuestionsProjectIdAppIdPost( props.projectId, props.appId || '', answers ), { onSuccess: (data) => { - setEmailAssistantState(data); + setAppResponse(data); } } ); const submitFeedbackMutation = useMutation( (feedbacks: Feedback) => - DefaultService.provideFeedbackApiV0EmailAssistantProvideFeedbackProjectIdAppIdPost( + DefaultService.provideFeedbackApiV0EmailAssistantTypedProvideFeedbackProjectIdAppIdPost( props.projectId, props.appId || '', feedbacks ), { onSuccess: (data) => { - setEmailAssistantState(data); + setAppResponse(data); } } ); @@ -273,13 +279,12 @@ export const EmailAssistant = (props: { projectId: string; appId: string | undef return ; } const displayValidationError = validationData !== null; - const displayInstructions = emailAssistantState === null && !displayValidationError; - const displayInitialDraft = emailAssistantState !== null; - const displaySubmitAnswers = - displayInitialDraft && emailAssistantState.next_step !== 'process_input'; + const displayInstructions = appResponse === null && !displayValidationError; + const displayInitialDraft = appResponse !== null; + const displaySubmitAnswers = displayInitialDraft && appResponse.next_step !== 'process_input'; const displaySubmitFeedback = - displaySubmitAnswers && emailAssistantState.next_step !== 'clarify_instructions'; - const displayFinalDraft = displaySubmitFeedback && emailAssistantState.next_step === null; + displaySubmitAnswers && appResponse.next_step !== 'clarify_instructions'; + const displayFinalDraft = displaySubmitFeedback && appResponse.next_step === null; return (

{'Learn Burr '}

@@ -303,30 +308,30 @@ export const EmailAssistant = (props: { projectId: string; appId: string | undef submitInitial={(initial) => { submitInitialMutation.mutate(initial); }} - responseInstructions={emailAssistantState?.response_instructions} - emailToRespond={emailAssistantState?.email_to_respond} + responseInstructions={appResponse.state?.response_instructions || null} + emailToRespond={appResponse.state?.email_to_respond || null} /> )}
{displaySubmitAnswers && ( { submitAnswersMutation.mutate(answers); }} - questions={emailAssistantState.questions} - answers={emailAssistantState.answers} + questions={appResponse.state.questions?.question || null} + answers={appResponse.state.answers?.answers || null} isLoading={anyMutationLoading} /> )} {displaySubmitFeedback && ( { submitFeedbackMutation.mutate(feedbacks); }} - drafts={emailAssistantState.drafts} - feedbacks={emailAssistantState.feedback_history} + drafts={appResponse.state.draft_history || null} + feedbacks={appResponse.state.feedback_history || null} isLoading={anyMutationLoading} /> )} @@ -335,7 +340,9 @@ export const EmailAssistant = (props: { projectId: string; appId: string | undef

Final Draft

-              {emailAssistantState.drafts?.[emailAssistantState.drafts.length - 1]}
+              {appResponse.state.current_draft?.subject +
+                '\n' +
+                appResponse.state.current_draft?.contents || ''}