Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[editor][easy] Add 'model' to relevant Prompt Schemas #801

Merged
merged 3 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions python/src/aiconfig/editor/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"oboe": "^2.1.5",
"react": "^18",
"react-dom": "^18",
"react-error-boundary": "^4.0.12",
"react-markdown": "^8.0.6",
"react-scripts": "5.0.1",
"remark-gfm": "^4.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ActionIcon, Tooltip } from "@mantine/core";
import { IconBraces, IconBracesOff } from "@tabler/icons-react";

type Props = {
isRawJSON: boolean;
setIsRawJSON: (value: boolean) => void;
};

export default function JSONEditorToggleButton({
isRawJSON,
setIsRawJSON,
}: Props) {
return (
<Tooltip label="Toggle JSON editor" withArrow>
<ActionIcon onClick={() => setIsRawJSON(!isRawJSON)}>
{isRawJSON ? <IconBracesOff size="1rem" /> : <IconBraces size="1rem" />}
</ActionIcon>
</Tooltip>
);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import ModelSettingsSchemaRenderer from "./ModelSettingsSchemaRenderer";
import { GenericPropertiesSchema } from "../../../utils/promptUtils";
import { ActionIcon, Flex, Tooltip, createStyles } from "@mantine/core";
import { Flex, Text, createStyles } from "@mantine/core";
import { JSONObject } from "aiconfig";
import { memo, useState } from "react";
import { IconBraces, IconBracesOff } from "@tabler/icons-react";
import JSONRenderer from "../../JSONRenderer";
import JSONEditorToggleButton from "../../JSONEditorToggleButton";
import { ErrorBoundary, useErrorBoundary } from "react-error-boundary";

type Props = {
settings?: JSONObject;
Expand All @@ -22,6 +23,35 @@ const useStyles = createStyles(() => ({
},
}));

type ErrorFallbackProps = {
settings?: JSONObject;
toggleJSONEditor: () => void;
};

function SettingsErrorFallback({
settings,
toggleJSONEditor,
}: ErrorFallbackProps) {
const { resetBoundary: clearRenderError } = useErrorBoundary();
return (
<Flex direction="column">
<Text color="red" size="sm">
<Flex justify="flex-end">
<JSONEditorToggleButton
isRawJSON={false}
setIsRawJSON={() => {
clearRenderError();
toggleJSONEditor();
}}
/>
</Flex>
Invalid settings format for model. Toggle JSON editor to update
</Text>
<JSONRenderer content={settings} />
</Flex>
);
}

export default memo(function ModelSettingsRenderer({
settings,
schema,
Expand All @@ -30,37 +60,45 @@ export default memo(function ModelSettingsRenderer({
const { classes } = useStyles();
const [isRawJSON, setIsRawJSON] = useState(schema == null);

const rawJSONToggleButton = (
<Flex justify="flex-end">
<JSONEditorToggleButton
isRawJSON={isRawJSON}
setIsRawJSON={setIsRawJSON}
/>
</Flex>
);

return (
<Flex direction="column" className={classes.settingsContainer}>
{/* // TODO: Refactor this out to a generic wrapper for toggling JSONRenderer or children component */}
{/* // Only show the toggle if there is a schema to toggle between JSON and custom schema renderer */}
{schema && (
<Flex justify="flex-end">
<Tooltip label="Toggle JSON editor" withArrow>
<ActionIcon onClick={() => setIsRawJSON((curr) => !curr)}>
{isRawJSON ? (
<IconBracesOff size="1rem" />
) : (
<IconBraces size="1rem" />
)}
</ActionIcon>
</Tooltip>
</Flex>
)}
{isRawJSON || !schema ? (
<JSONRenderer
content={settings}
onChange={(val) =>
onUpdateModelSettings(val as Record<string, unknown>)
}
// schema={schema} TODO: Add schema after fixing z-index issue
/>
<>
{/* // Only show the toggle if there is a schema to toggle between JSON and custom schema renderer */}
{schema && rawJSONToggleButton}
<JSONRenderer
content={settings}
onChange={(val) =>
onUpdateModelSettings(val as Record<string, unknown>)
}
// schema={schema} TODO: Add schema after fixing z-index issue
/>
</>
) : (
<ModelSettingsSchemaRenderer
settings={settings}
schema={schema}
onUpdateModelSettings={onUpdateModelSettings}
/>
<ErrorBoundary
fallbackRender={() => (
<SettingsErrorFallback
settings={settings}
toggleJSONEditor={() => setIsRawJSON(true)}
/>
)}
>
{rawJSONToggleButton}
<ModelSettingsSchemaRenderer
settings={settings}
schema={schema}
onUpdateModelSettings={onUpdateModelSettings}
/>
</ErrorBoundary>
)}
</Flex>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,63 @@ import { memo, useState } from "react";
import { PromptInputSchema } from "../../../utils/promptUtils";
import PromptInputSchemaRenderer from "./schema_renderer/PromptInputSchemaRenderer";
import PromptInputConfigRenderer from "./PromptInputConfigRenderer";
import { ActionIcon, Flex, Tooltip } from "@mantine/core";
import { IconBraces, IconBracesOff } from "@tabler/icons-react";
import { Flex } from "@mantine/core";
import PromptInputJSONRenderer from "./PromptInputJSONRenderer";
import { ErrorBoundary, useErrorBoundary } from "react-error-boundary";
import { Text } from "@mantine/core";
import JSONRenderer from "../../JSONRenderer";
import JSONEditorToggleButton from "../../JSONEditorToggleButton";

type Props = {
input: PromptInput;
schema?: PromptInputSchema;
onChangeInput: (value: PromptInput) => void;
};

type ErrorFallbackProps = {
input: PromptInput;
toggleJSONEditor: () => void;
};

function InputErrorFallback({ input, toggleJSONEditor }: ErrorFallbackProps) {
const { resetBoundary: clearRenderError } = useErrorBoundary();
return (
<Flex direction="column">
<Text color="red" size="sm">
Invalid input format for model. Toggle JSON editor to update
</Text>
<JSONRenderer content={input} />
<Flex justify="flex-end">
<JSONEditorToggleButton
isRawJSON={false}
setIsRawJSON={() => {
clearRenderError();
toggleJSONEditor();
}}
/>
</Flex>
</Flex>
);
}

export default memo(function PromptInputRenderer({
input,
schema,
onChangeInput,
}: Props) {
const [isRawJSON, setIsRawJSON] = useState(false);
return (
const rawJSONToggleButton = (
<Flex justify="flex-end">
<JSONEditorToggleButton
isRawJSON={isRawJSON}
setIsRawJSON={setIsRawJSON}
/>
</Flex>
);

const nonJSONRenderer = (
<>
{isRawJSON ? (
<PromptInputJSONRenderer input={input} onChangeInput={onChangeInput} />
) : schema ? (
{schema ? (
<PromptInputSchemaRenderer
input={input}
schema={schema}
Expand All @@ -35,17 +71,34 @@ export default memo(function PromptInputRenderer({
onChangeInput={onChangeInput}
/>
)}
<Flex justify="flex-end">
<Tooltip label="Toggle JSON editor" withArrow>
<ActionIcon onClick={() => setIsRawJSON((curr) => !curr)}>
{isRawJSON ? (
<IconBracesOff size="1rem" />
) : (
<IconBraces size="1rem" />
)}
</ActionIcon>
</Tooltip>
</Flex>
{rawJSONToggleButton}
</>
);

return (
<>
{isRawJSON ? (
<>
<PromptInputJSONRenderer
input={input}
onChangeInput={onChangeInput}
/>
{rawJSONToggleButton}
</>
) : (
<ErrorBoundary
fallbackRender={() => (
<InputErrorFallback
input={input}
// Fallback is only shown when an error occurs in non-JSON renderer
// so toggle must be to JSON editor
toggleJSONEditor={() => setIsRawJSON(true)}
/>
)}
>
{nonJSONRenderer}
</ErrorBoundary>
)}
</>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ function SchemaRenderer({ input, schema, onChangeInput }: SchemaRendererProps) {
} = schema.properties;

if (typeof input === "string") {
return null;
// TODO: Add ErrorBoundary handling and throw error here
throw new Error("Expected input type object but got string");
}

const { data, attachments, ..._restData } = input;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export const DalleImageGenerationParserPromptSchema: PromptSchema = {
model_settings: {
type: "object",
properties: {
model: {
type: "string",
},
Comment on lines +13 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what these are used for. Why do we need to have this type: "string" field?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This determines how the setting property 'model' is rendered in the nice settings renderer:
Screenshot 2024-01-08 at 10 42 56 AM

The PromptSchema is a way for model parsers to define what their input, model settings and metadata are structured like, because they are otherwise entirely generic. Without this static schema we have no way of knowing what to render for these prompts

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add description in the info text so people know what this is for? I'm still not really sure. How is this different from the select model top right selector on each prompt?

Copy link
Contributor Author

@rholinshead rholinshead Jan 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add a description but the descriptions are specific to each parser's prompt schema implementation. For openai for example, model description from https://platform.openai.com/docs/api-reference/chat/create is

ID of the model to use. See the model endpoint compatibility table for details on which models work with the Chat API.

Description tooltips don't support markdown so there's no way to nicely add an external link as hyperlink (also, don't know if we would want to support that since custom parsers could then technically add malicious hyperlinks ?)

How is this different from the select model top right selector on each prompt

The select model top right selector is technically not even a model right now since AIConfig allows us to register arbitrary ids for models when registering model parsers. Take HuggingFaceTextGenerationParser for example, we register "HuggingFaceTextGenerationParser": "HuggingFaceTextGenerationParser" as parser and model id. So if we don't have a 'model' option in the settings there is no way to specify what model to actually use for the API call. Same for AnyscaleEndpoint.

Also, technically the case for gpt-4, etc (until #783 lands), since we register the model/parser as "gpt-4": "gpt-4" but pull the actual model for the API from the settings (not from model name in the prompt metadata).

#782 goes into more details, but as-is we can't really use the top-right model selector as specifying the actual model to use for the prompt api request as a result of the parser/model confusion

n: {
type: "integer",
minimum: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ export const OpenAIChatModelParserPromptSchema: PromptSchema = {
model_settings: {
type: "object",
properties: {
model: {
type: "string",
},
system_prompt: {
type: "string",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export const PaLMChatParserPromptSchema: PromptSchema = {
model_settings: {
type: "object",
properties: {
model: {
type: "string",
},
context: {
type: "string",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export const PaLMTextParserPromptSchema: PromptSchema = {
model_settings: {
type: "object",
properties: {
model: {
type: "string",
},
candidate_count: {
type: "integer",
minimum: 1,
Expand Down
7 changes: 7 additions & 0 deletions python/src/aiconfig/editor/client/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9594,6 +9594,13 @@ [email protected]:
file-selector "^0.6.0"
prop-types "^15.8.1"

react-error-boundary@^4.0.12:
version "4.0.12"
resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-4.0.12.tgz#59f8f1dbc53bbbb34fc384c8db7cf4082cb63e2c"
integrity sha512-kJdxdEYlb7CPC1A0SeUY38cHpjuu6UkvzKiAmqmOFL21VRfMhOcWxTCBgLVCO0VEMh9JhFNcVaXlV4/BTpiwOA==
dependencies:
"@babel/runtime" "^7.12.5"

react-error-overlay@^6.0.11:
version "6.0.11"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb"
Expand Down