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] Support Updating AIConfig State when aiconfig Prop Changes #1261

Merged
merged 1 commit into from
Feb 21, 2024

Conversation

rholinshead
Copy link
Contributor

@rholinshead rholinshead commented Feb 20, 2024

[editor] Support Updating AIConfig State when aiconfig Prop Changes

Reviving the changes closed in #960 so that we can leverage the aiconfig prop to the AIConfigEditor component for updating the config in state. This will be useful for 2 reason in the vscode extension:

  1. Currently, re-saturating the webview has no aiconfig in state. This causes an empty webview (with loading spinner) in the case where the server has issues and can't load the content (e.g. if the config JSON has invalid model parsers defined at the top). We can improve that UX to have a readonly copy of the config by saving the aiconfig if webview context to re-saturate with. The problem with doing that right now is that the /load call after the editor renders would not update the editor with the loaded config, which means it could be showing a stale config. This PR would fix that
  2. Undo/redo. Similar to the above, in vscode extension undo/redo is controlled by the webview extension host and updates the server with the updated state. This then propagates the updated aiconfig to the webview client, which currently does nothing with the updated config. This PR would fix that as well

An important note here:

When an updated aiconfig prop is passed, we just replace the entire aiconfig state in the editor, instead of consolidating with existing state. This will ensure:

  • new prompt keys are set in the _ui, meaning the prompts are remounted (so, undo/redo will replace the input properly)
  • config passed through is the source of truth, instead of having a weird case where client state is persisted / overwriting the provided config, causing incorrect state

We can consider the scenario of passing updated aiconfig prop through as treating the editor as a controlled component, at least temporarily. As a 'user' of the component, one would expect passing a new aiconfig prop would make the editor have that exact contents.

Lastly, just noting we could do some smarter consolidation using lodash deep equality checks in order to retain existing prompts that are unchanged when passing a new aiconfig prop through (so, they'd keep their _ui.id and not be remounted). Just noting that there would probably be no perf benefit (since deep equality check may be just as expensive as rerendering the components, if not more). The only benefit could be in improving the UX if the current implementation causes weirdness. For example, in the test video there is some flickering of the audio input as it re-renders, but I'm not sure if that warrants the expensive equality checks on its own

Testing:

Updated LocalEditor to leverage state instead of callbacks for streaming:

output_chunk: (data) => {
            //onStream({ type: "output_chunk", data: data as Output });
            const output = data as Output;
            setAiConfig(
              (prev) =>
                ({
                  ...prev,
                  prompts: prev!.prompts.map((prompt) => {
                    if (prompt.name === "get_activities") {
                      return { ...prompt, outputs: [output] };
                    }
                    return prompt;
                  }),
                } as AIConfig)
            );
          },
          aiconfig_chunk: (data) => {
            //onStream({ type: "aiconfig_chunk", data: data as AIConfig });
            setAiConfig(data as AIConfig);
          },

Then make sure streaming works

Screen.Recording.2024-02-20.at.11.07.46.AM.mov

Note that in the video I'm also clicking into the input to show that it's continuously re-rendered, so user cannot actually click and edit it while the state is changing from the streaming

Copy link
Contributor

@saqadri saqadri left a comment

Choose a reason for hiding this comment

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

Incredible writeup of the various cases and options considered. This change looks good to me. Main question -- did you check this in the vscode editor? I tried this from #960 when I was building the VSCode editor, and it didn't seem to propagate updates properly. However, it's possible that some of the other fixes you made to re-render as state changes were the missing piece.

@rholinshead
Copy link
Contributor Author

Incredible writeup of the various cases and options considered. This change looks good to me. Main question -- did you check this in the vscode editor? I tried this from #960 when I was building the VSCode editor, and it didn't seem to propagate updates properly. However, it's possible that some of the other fixes you made to re-render as state changes were the missing piece.

Ah, no I didn't try it out since I'm not sure the best way to do that besides pulling my aiconfig-editor package PR and rebasing this on top and linking it; how did you test out #960 before?
Fwiw, the change of overwriting the state (mainly, the fact that the ClientPrompts have new ids/keys) is what will 'fix' the issue you saw

@saqadri
Copy link
Contributor

saqadri commented Feb 21, 2024

how did you test out #960 before?

With difficulty. I copied the VSCodeEditor.tsx (and related files) into the aiconfig-editor folder, built the main.js bundle from there, and copied it into the vscode-extension folder lol. Probably overkill and better to just publish a package update.

One thing I'd suggest is we should have a test-aiconfig-editor package on npm that we update to test stuff out as needed. But also feel free to push an update to the main package directly right now to test it out.

@rholinshead
Copy link
Contributor Author

how did you test out #960 before?

With difficulty. I copied the VSCodeEditor.tsx (and related files) into the aiconfig-editor folder, built the main.js bundle from there, and copied it into the vscode-extension folder lol. Probably overkill and better to just publish a package update.

One thing I'd suggest is we should have a test-aiconfig-editor package on npm that we update to test stuff out as needed. But also feel free to push an update to the main package directly right now to test it out.

Ah, ok, that's what I feared :s

I was planning to publish and bump the minor version with this since it does add some new behaviour that changes how the editor behaves.

I can publish to a test package and update test plan for vscode, but will land first so it's easier to do that without dealing with additional merge issues

@rholinshead rholinshead merged commit 6f1ea15 into main Feb 21, 2024
1 check passed
rholinshead added a commit that referenced this pull request Feb 21, 2024
…1279)

# [editor][rfc] Skip Updating Webview if there are No Content Changes

Apparently, `changeDocumentSubscription` event is also fired even when
no `contentChanges` exist. When trying to update aiconfig-editor package
to support updating aiconfig state via param (from
#1261), this fact causes a
bug where the current input is remounted as I'm typing due to the
`changeDocumentSubscription` event being called with no changes. We can
fix this by preventing this scenario from updating the webview with
duplicate content (which would be serialized as a new, but identical,
aiconfig object being passed to the AIConfigEditor component).

This is just 1 of 3 possible ways to resolve this issue. The others are:
2. continue updating webview in this case, but do a deep equality check
on the client and no-op instead of setting the aiconfig in state there
3. continue update the webview and also update aiconfig in state, but
update handling of aiconfig prop in the editor component to do deep
equality checks

I picked this since it's the easiest and most performant. I could be
easily persuaded to do 2 if it's possible the aiconfig in state could
differ from the *existing* document in the extension host (in which
case, we would want to update the client even if document content
matches existing content).

Not a fan of 3 since it's a larger perf hit and kind of goes against the
intentions of memoized component props.

To give an idea of the issue, this is what happens when I update our
extension editor to use aiconfig-editor-test package published with the
changes from #1261:



https://github.com/lastmile-ai/aiconfig/assets/5060851/53e1ff11-e686-41cc-9604-102449ca8f1e



And, with this PR's changes, the issue is fixed:


https://github.com/lastmile-ai/aiconfig/assets/5060851/80419b4d-ad2b-441e-8d5e-44da97551a94
rholinshead added a commit that referenced this pull request Feb 21, 2024
# [editor] Bump aiconfig-editor Version to 0.2.0

Bump the version to now have the changes from #1261. Ensure the editor
works. Also, undo/redo now works:


https://github.com/lastmile-ai/aiconfig/assets/5060851/6abb5f4c-072e-491b-84ba-769ebbcd2e42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants