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

Generate cells using Foyle AI #1356

Merged
merged 19 commits into from
May 23, 2024
Merged

Generate cells using Foyle AI #1356

merged 19 commits into from
May 23, 2024

Conversation

jlewi
Copy link
Contributor

@jlewi jlewi commented May 16, 2024

  • Create a command which sends an RPC to Foyle to generate cells
  • Resulting cells are inserted into the notebook
  • A configuration option lets user set the address of the Foyle server

Related to stateful/runme#574

// cellToCellData converts a NotebookCell to a NotebookCellData.
// NotebookCell is an interface used by the editor.
// NotebookCellData is a concrete class.
export function cellToCellData(cell: vscode.NotebookCell): vscode.NotebookCellData {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sourishkrout Do I need these conversion routines to convert between the protos and vscode's native data structures? Are there existing routines I can reuse?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. I updated the code to reuse the existing routines.
We cell need the function cellToCellData though because that converts from the vscode API obtained from the editor into the API used by the serialization routines.

I also had to make one of the serializer methods public.

Copy link
Member

@sourishkrout sourishkrout May 21, 2024

Choose a reason for hiding this comment

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

@jlewi is there maybe a file missing in the latest commits?

in src/extension/ai/generate.ts
image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sourishkrout Can you help me figure out what's going on here and how to fix it. I think it should have been

import {Serializer} from '../../types'

I'm trying to import Notebook defined here.

I'm trying to instantiate an instance of Notebook to pass to Notebook.Revive here
https://github.com/stateful/vscode-runme/pull/1356/files#diff-7561d1e499859730c4937494e85d7dddfbe11332a496476afc5d082860df7335R81

What's the proper way

  1. Instantiate a notebook
  2. Populate the cells in the notebook with the proto

I'm a little confused by what's going on. I see the error in vscode but npm run bundle succeeds and I thought I had installed it successfully from source.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So I think I partially understand the error. Serializer.Notebook is a type not a class so I can't use new. I wrote some conversion code to convert the proto type to the Serializer.CellType

PTAL

Copy link
Member

@sourishkrout sourishkrout May 23, 2024

Choose a reason for hiding this comment

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

Correct. The Serializer.Notebook is a type that in structural typing sense fits different Parsers. Runme has a legacy WASM-based parser from its prototype days. It made it possible to transparently switching between them.

Using your latest commits fixed the error for me. The additional conversion code is necessary to satisfy the structure required by the type. If we removed the legacy WASM-parser we could probably just absorb this code into the lower layer.

I have seen the Typescript LSP and/or the ESlint LSP getting "confused" which happens when files are being moved around right under it. The easy fix is to restart them using the command palette. In any case, it compiles cleanly now on all fronts webpack/tsc, and eslint & typescript LSPs. Likely a side-effects of linter, bundler/linker, etc not being integral to node.

cellPb.kind = CellKind.MARKUP
}

// TODO(jeremy): cell.metadata is type map[string]Any; cellPb.metadata is type map[string]string
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sourishkrout Is there existing conversion code I can use here? If not is there a way to do this other than just testing if the values are strings and if not ignoring them?

Copy link
Member

Choose a reason for hiding this comment

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

I believe this static method is what you're looking for:

https://github.com/stateful/vscode-runme/blob/main/src/extension/serializer.ts#L740-L757

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks.
Done.

@jlewi jlewi marked this pull request as ready for review May 16, 2024 23:10
@jlewi
Copy link
Contributor Author

jlewi commented May 16, 2024

@sourishkrout Would you PTAL? The code is a bit rough (lots of lint errors); however I had some questions about how various things should be done and I thought you might be able to provide some pointers?

FWIW the code does work; I was able to run it and get suggestions provided by Foyle

Copy link
Member

@sourishkrout sourishkrout left a comment

Choose a reason for hiding this comment

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

Overall good stuff. Filled in some gaps for you. Hopefully the requested changes are reasonable to get this merged.

I think it's probably wise to forgo unit tests with mocking for the app/UI logic and e2e integration tests until the integration moves out of alpha.

package.json Outdated
"command": "runme.aiGenerate",
"key": "win+;",
"mac": "cmd+;",
"when": "resourceExtname==.md || resourceExtname==.markdown"
Copy link
Member

Choose a reason for hiding this comment

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

notebookType == runme might be a better choice here instead of keying on file extension

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


// TODO(jeremy): Should we take transport as an argument?
export function initAIServiceClient(): AIServiceClient {
const config = vscode.workspace.getConfiguration(extName)
Copy link
Member

Choose a reason for hiding this comment

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

nit, in runme-land we have a few zod-schemata-based abstractions to handle config. not super important right now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you point me at a code snippet for the right pattern?

Copy link
Member

Choose a reason for hiding this comment

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

it's all in src/utils/configuration.ts but we ok changing it post-merge

cellPb.kind = CellKind.MARKUP
}

// TODO(jeremy): cell.metadata is type map[string]Any; cellPb.metadata is type map[string]string
Copy link
Member

Choose a reason for hiding this comment

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

I believe this static method is what you're looking for:

https://github.com/stateful/vscode-runme/blob/main/src/extension/serializer.ts#L740-L757

// cellToCellData converts a NotebookCell to a NotebookCellData.
// NotebookCell is an interface used by the editor.
// NotebookCellData is a concrete class.
export function cellToCellData(cell: vscode.NotebookCell): vscode.NotebookCellData {
Copy link
Member

Choose a reason for hiding this comment

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

src/extension/ai/generate.ts Show resolved Hide resolved
tests/extension/ai/converters.test.ts Outdated Show resolved Hide resolved
export const extName = 'runme'

// TODO(jeremy): Should we take transport as an argument?
export function initAIServiceClient(): AIServiceClient {
Copy link
Member

Choose a reason for hiding this comment

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

we've been keeping the gRPC related abstractions under https://github.com/stateful/vscode-runme/tree/main/src/extension/grpc. Including re-exporting the generated protos, e.g. https://github.com/stateful/vscode-runme/blob/main/src/extension/grpc/projectTypes.ts.

This allows us to avoid spreading these long imports '@buf/stateful_runme.community_timostamm-protobuf-ts/runme/ai/v1alpha1/ai_pb.client' across the code base and helps with API version migration down the road.

Can always do this later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

package.json Show resolved Hide resolved
this.registerTerminalProfile(),
)

// DO NOT COMMIT this was a hack because I was getting crashes when trying to run the extension
Copy link
Member

Choose a reason for hiding this comment

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

let's figure out what's going on - sooner or later the lack of running these handlers will rear it's ugly head

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems to be working for me now. I have no idea what changed. I uninstalled the extension and reinstalled it as part of trying to install a dev version of the extension in my vscode; so maybe it was that 🤷

Copy link
Contributor Author

@jlewi jlewi left a comment

Choose a reason for hiding this comment

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

Thanks @sourishkrout . I believe I've addressed all your comments with the exception of the zota config issue and the experiments flag; see my replies to those comments.

package.json Show resolved Hide resolved
package.json Outdated
"command": "runme.aiGenerate",
"key": "win+;",
"mac": "cmd+;",
"when": "resourceExtname==.md || resourceExtname==.markdown"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


// TODO(jeremy): Should we take transport as an argument?
export function initAIServiceClient(): AIServiceClient {
const config = vscode.workspace.getConfiguration(extName)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you point me at a code snippet for the right pattern?

// cellToCellData converts a NotebookCell to a NotebookCellData.
// NotebookCell is an interface used by the editor.
// NotebookCellData is a concrete class.
export function cellToCellData(cell: vscode.NotebookCell): vscode.NotebookCellData {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. I updated the code to reuse the existing routines.
We cell need the function cellToCellData though because that converts from the vscode API obtained from the editor into the API used by the serialization routines.

I also had to make one of the serializer methods public.

cellPb.kind = CellKind.MARKUP
}

// TODO(jeremy): cell.metadata is type map[string]Any; cellPb.metadata is type map[string]string
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks.
Done.

src/extension/ai/generate.ts Show resolved Hide resolved
package.json Show resolved Hide resolved
this.registerTerminalProfile(),
)

// DO NOT COMMIT this was a hack because I was getting crashes when trying to run the extension
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems to be working for me now. I have no idea what changed. I uninstalled the extension and reinstalled it as part of trying to install a dev version of the extension in my vscode; so maybe it was that 🤷

export const extName = 'runme'

// TODO(jeremy): Should we take transport as an argument?
export function initAIServiceClient(): AIServiceClient {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@sourishkrout sourishkrout self-requested a review May 21, 2024 21:41
Copy link
Member

@sourishkrout sourishkrout left a comment

Choose a reason for hiding this comment

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

Won't compile/build locally right now... likely due to a missing file? See comments.

Otherwise 👍 .

@jlewi
Copy link
Contributor Author

jlewi commented May 22, 2024

@sourishkrout Sorry about that. I think its fixed.

value: cell.value,
metadata: cell.metadata,
kind: kind,
// TODO(jeremy): Should we include outputs? The generate response should never contain outputs so we shouldn't
Copy link
Member

Choose a reason for hiding this comment

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

fyi, outputs are entirely optional in Runme. We only need them when recording of Session files is enabled which writes to a "carbon copy" of the original markdown notebook; never back to the original source file.

Copy link
Member

@sourishkrout sourishkrout left a comment

Choose a reason for hiding this comment

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

👍 LGTM

@sourishkrout
Copy link
Member

sourishkrout commented May 23, 2024

One of the unit tests failed which is an easy fix. registerCommand is called an additional time for the Foyle/AI cmd.

@jlewi the fix is to increment it to 40.

 FAIL  tests/extension/extension.test.ts > initializes all providers
AssertionError: expected "spy" to be called 39 times, but got 40 times
 ❯ tests/extension/extension.test.ts:102:36
    100|   expect(notebooks.registerNotebookCellStatusBarItemProvider).toBeCall…
    101|   expect(workspace.registerNotebookSerializer).toBeCalledTimes(1)
    102|   expect(commands.registerCommand).toBeCalledTimes(39)
       |                                    ^
    103|   expect(window.registerTreeDataProvider).toBeCalledTimes(1)
    104|   expect(window.registerUriHandler).toBeCalledTimes(1)

Error: AssertionError: expected "spy" to be called 39 times, but got 40 times
 ❯ tests/extension/extension.test.ts:102:36

@jlewi
Copy link
Contributor Author

jlewi commented May 23, 2024

Thank you @sourishkrout ; I fixed the test.

@sourishkrout
Copy link
Member

Merging. - The e2e integration test's failing because GitHub Actions are being finicky and have been under the weather with outages the last few days. It's not broken.

@sourishkrout sourishkrout merged commit 066838d into stateful:main May 23, 2024
2 of 3 checks passed
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