Skip to content

Commit

Permalink
Remove MDX repair machinery (#497)
Browse files Browse the repository at this point in the history
This removes the automatic attempt to repair MDX -- instead, it
explicitly allows for invalid MDX to be emitted at the end of the stream
(but not during intermediate states).

Additionally, explicitly mark the `AssistantMessage` with `contentType:
"text/mdx"`.
  • Loading branch information
petersalas committed Nov 16, 2023
1 parent 03f2c72 commit c5501a1
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 98 deletions.
2 changes: 1 addition & 1 deletion packages/ai-jsx/package.json
Expand Up @@ -4,7 +4,7 @@
"repository": "fixie-ai/ai-jsx",
"bugs": "https://github.com/fixie-ai/ai-jsx/issues",
"homepage": "https://ai-jsx.com",
"version": "0.25.0",
"version": "0.26.0",
"volta": {
"extends": "../../package.json"
},
Expand Down
101 changes: 5 additions & 96 deletions packages/ai-jsx/src/batteries/sidekick/platform/conversation.tsx
Expand Up @@ -4,13 +4,10 @@ import remarkMath from 'remark-math';
import { compile } from '@mdx-js/mdx';
import { ChatCompletion } from '../../../core/completion.js';
import {
UserMessage,
AssistantMessage,
FunctionResponse,
ConversationMessage,
Shrinkable,
renderToConversation,
SystemMessage,
ShowConversation,
} from '../../../core/conversation.js';
import { LargeFunctionResponseWrapper, redactedFunctionTools } from './large-response-handler.js';
Expand Down Expand Up @@ -61,8 +58,8 @@ export function getShrinkableConversation(messages: ConversationMessage[], fullC
export function present(conversationElement: ConversationMessage, outputFormat: SidekickOutputFormat) {
if (conversationElement.type === 'assistant' && outputFormat === 'text/mdx') {
return (
<AssistantMessage>
<LimitToValidMdx>{conversationElement.element}</LimitToValidMdx>
<AssistantMessage metadata={{ contentType: 'text/mdx' }}>
<LimitToValidMdxWhileStreaming>{conversationElement.element}</LimitToValidMdxWhileStreaming>
</AssistantMessage>
);
}
Expand Down Expand Up @@ -187,7 +184,7 @@ export function getNextConversationStep(
);
}

return outputFormat === 'text/mdx' ? <RepairMdxInConversation>{generation}</RepairMdxInConversation> : generation;
return generation;
}
default:
return null;
Expand All @@ -206,98 +203,10 @@ async function getMdxCompileError(mdx: string) {
}
}

async function* RepairMdxInConversation(
async function* LimitToValidMdxWhileStreaming(
{ children }: { children: AI.Node },
{ render, memo, logger }: AI.ComponentContext
{ render, logger }: AI.ComponentContext
) {
/**
* I feel like I saw cases where this would still stream invalid MDX to the client,
* but now I can't repro.
*/

const memoChildren = memo(children);
yield memoChildren;
const conversation = await renderToConversation(memoChildren, render);
return Promise.all(
conversation.map(async ({ element }) => {
if (element.tag !== AssistantMessage) {
return element;
}
const content = await render(element);
const mdxCompileError = await getMdxCompileError(content);
if (mdxCompileError) {
logger.info({ mdx: content, mdxCompileError }, 'Repairing invalid MDX');

/**
* This will stream back the entire response, which can be inefficient if the response is
* mostly fine but there's just a missing escape character towards the end. If we wanted
* to be more clever, we could try to figure out what the invalid MDX subset was, and just
* repair that. Or have the model give us some sort of diff format to apply.
*/
return <RepairMdx>{content}</RepairMdx>;
}
return element;
})
);
}

// TODO: what if the MDX is still invalid? We should either retry or give a clear error message to the user.
function RepairMdx({ children }: { children: string }) {
return (
<ChatCompletion>
{/* This message is similar to the one in ai-jsx's MDX system message, but I didn't want
to try to share because I'm skeptical overall on the value of sharing prompts.
*/}
<SystemMessage>
You are an expert with MDX. which is Markdown For the Component Era. Here are instructions for how to use MDX:
=== Begin instructions MDX allows you to use JSX in your markdown content. You can import components, such as
interactive charts or alerts, and embed them within your content. This makes writing long-form content with
components a blast. More practically MDX can be explained as a format that combines markdown with JSX and looks
as follows: === Begin example
{`
Here is some markdown text
<MyComponent id="123" />
# Here is more markdown text
<Component
open
x={1}
label={'this is a string, *not* markdown!'}
icon={<Icon />}
/>`}
* Markdown list item 1 * Markdown list item 2 * Markdown list item 3 === end example === end instructions Do not
include a starting ```mdx and closing ``` line. Just respond with the MDX itself. Do not include extra
whitespace that is not needed for the markdown interpretation. For instance, if your component has a prop that's
a JSON object, put it all on one line:
{"<Component prop={[[{ key: 'value' }, { long: 'field' }]]} />"}
This doc tells you the differences between MDX and markdown. === Start doc ### 7.2 Deviations from Markdown MDX
adds constructs to Markdown but also prohibits certain normal Markdown constructs. #### 7.2.2 Indented code
Indentation to create code blocks is not supported. Instead, use fenced code blocks. The reason for this change
is so that elements can be indented. Correct: ```js console.log(1) ``` #### 7.2.3 Autolinks Autolinks are not
supported. Instead, use links or references. The reason for this change is because whether something is an
element (whether HTML or JSX) or an autolink is ambiguous{' '}
{'(Markdown normally treats `<svg:rect>`, `<xml:lang/>`, or `<svg:circle{...props}>` as links)'}. ## Quotes In
MDX, be sure to use the proper quote type so quote characters in the string do not break the syntax. For
instance:
{`
<A foo='bar " baz' />
<A foo="I'm" />
<A foo={\`I'm "good"\`} />
`}
You cannot escape quotes with a \. You must use the proper quote type. ## {'{'} and {'}'} characters In MDX, the{' '}
{'{'} and {'}'} characters are used to refer to variables, but you don't have any variables available, so you
shouldn't use those characters. If you use them because they're otherwise necessary in prose, you must escape
them: Example 1: The handlebars template language looks like: \`\{'{'}\{'{'}foo\{'}'}\{'}'}\` Example 2: The
handlebars template language looks like: `{'{{'}foo{'}}'}` The user will give you a message that has invalid
MDX. Return the MDX, fixed to be valid. Do not include any other prose. Respond only with the MDX.
</SystemMessage>
<UserMessage>{children}</UserMessage>
</ChatCompletion>
);
}

async function* LimitToValidMdx({ children }: { children: AI.Node }, { render, logger }: AI.ComponentContext) {
const rendered = render(children);
for await (const frame of rendered) {
const mdxCompileError = await getMdxCompileError(frame);
Expand Down
12 changes: 11 additions & 1 deletion packages/docs/docs/changelog.md
@@ -1,6 +1,16 @@
# Changelog

## 0.24.0
## 0.26.0

- In the `Sidekick` component:
- Remove the MDX repair attempt.
- Reduce standard system prompt size.

## [0.25.0](https://github.com/fixie-ai/ai-jsx/commit/e362a16f14f37d75415a89fb8846432e6e7fd89b)

- `Sidekick` can now interject with filler content (e.g. "Let me check on that.") when the model requests a function call.

## [0.24.0](https://github.com/fixie-ai/ai-jsx/commit/b72da82f592f0d9eba12b52b8e89e9abae51a7af)

- Update OpenAI client to 4.16.0
- Add support for OpenAI parallel function calls
Expand Down

4 comments on commit c5501a1

@vercel
Copy link

@vercel vercel bot commented on c5501a1 Nov 16, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

ai-jsx-voice – ./packages/voice

ai-jsx-voice.vercel.app
ai-jsx-voice-git-main-fixie-ai.vercel.app
ai-jsx-voice-fixie-ai.vercel.app
voice.fixie.ai

@vercel
Copy link

@vercel vercel bot commented on c5501a1 Nov 16, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

ai-jsx-nextjs-demo – ./packages/nextjs-demo

ai-jsx-nextjs-demo-fixie-ai.vercel.app
ai-jsx-nextjs-demo.vercel.app
ai-jsx-nextjs-demo-git-main-fixie-ai.vercel.app

@vercel
Copy link

@vercel vercel bot commented on c5501a1 Nov 16, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

ai-jsx-tutorial-nextjs – ./packages/tutorial-nextjs

ai-jsx-tutorial-nextjs-git-main-fixie-ai.vercel.app
ai-jsx-tutorial-nextjs.vercel.app
ai-jsx-tutorial-nextjs-fixie-ai.vercel.app

@vercel
Copy link

@vercel vercel bot commented on c5501a1 Nov 16, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

ai-jsx-docs – ./packages/docs

ai-jsx-docs-git-main-fixie-ai.vercel.app
ai-jsx-docs-fixie-ai.vercel.app
ai-jsx-docs.vercel.app
docs.ai-jsx.com

Please sign in to comment.