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

feature: Evaluations playground #2 #132

Merged
merged 1 commit into from
Sep 5, 2024
Merged

Conversation

geclos
Copy link
Collaborator

@geclos geclos commented Sep 3, 2024

Implements the import logs modal

@geclos geclos force-pushed the feature/evaluations_playground branch from 4b7f345 to db027e1 Compare September 4, 2024 12:06
}),
{ type: 'json' },
)
.handler(async ({ input, ctx }) => {
const commitsScope = new CommitsRepository(ctx.project.workspaceId)
const commit = await commitsScope
.getCommitById(input.commitId)
.getCommitByUuid({ uuid: input.commitUuid, project: ctx.project })
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice

@@ -81,7 +81,7 @@ describe('destroyDocumentAction', async () => {
it('fails when trying to remove a document from a merged commit', async () => {
const [_, error] = await destroyDocumentAction({
projectId: project.id,
commitId: merged.id,
commitUuid: merged.uuid,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this change?

Copy link
Collaborator Author

@geclos geclos Sep 5, 2024

Choose a reason for hiding this comment

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

we are working with commit uuids in the frontend constantly, using it in actions saves us one roundtrip to get the commit id

@geclos geclos force-pushed the feature/evaluations_playground branch from db027e1 to ad7ebac Compare September 5, 2024 06:49
@@ -28,13 +28,12 @@ export const addMessageHandler = factory.createHandlers(
workspace,
documentLogUuid,
messages,
providerLogHandler: (log) => {
// TODO: Review why this is possibly undefined now
queues.defaultQueue.jobs.enqueueCreateProviderLogJob!({
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this was wrong provider logs have to be saved in sync

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand but now the request takes longer. This is the tradeoff no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yup

@@ -42,16 +43,17 @@ export const runHandler = factory.createHandlers(
commit,
parameters,
providerLogHandler: (log) => {
queues.defaultQueue.jobs.enqueueCreateProviderLogJob({
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ditto

@geclos geclos force-pushed the feature/evaluations_playground branch from ad7ebac to dea4ce5 Compare September 5, 2024 06:56
},
}).then((r) => r.unwrap())

await pipeToStream(stream, result.stream)

// TODO: review if this is needed and why it's not in addMessages handler?
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@andresgutgon question for you ☝🏼

Copy link
Contributor

Choose a reason for hiding this comment

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

Need what? Sorry I don't understand

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

 queues.defaultQueue.jobs.enqueueCreateDocumentLogJob

this is being called here but it's not being called in the addMessages handler which also calls ai, I'm wondering if it should be removed from here or added to addMessages

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes because a document log is created when a document is run. But when a message is created only the logs for the AI are created (provider log)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

aaahm ok 👍🏼

Copy link
Contributor

Choose a reason for hiding this comment

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

Remove this comment in the next PR

}

return result
})
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i've implemented a regular REST get operation with filters instead of custom action for each type of get, this means that getProviderLogsForDocumentLogAction 👇🏼 is no longer needed

Copy link
Contributor

Choose a reason for hiding this comment

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

cool

@@ -28,7 +28,7 @@ export async function addMessagesAction({
const sdk = await createSdk().then((r) => r.unwrap())
const stream = createStreamableValue<ChainEvent, Error>()

const response = sdk.addMessges({
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ultra typo please be careful this is public api

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry about that.

</div>
</>
)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

very similar to document editor playground but not exactly the same. Probably some opportunities for DRYing but will evaluate later

@@ -61,7 +62,7 @@ export default function EvaluationEditor({
useEffect(() => {
readMetadata({
prompt: value,
withParameters: Object.keys(PARAMETERS_FROM_LOG),
// withParameters: ['messages', 'response'], // TODO: uncomment this line once I understand why it breaks
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

using withParamaters fails with a "variable not declared", have to debug the compiler. For now just commenting out since everything works without it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

cc @csansoon you probably can provide some light here

Copy link
Contributor

Choose a reason for hiding this comment

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

Unlike with documents, evaluations do not have the ability to create new variables just by referencing them in the code. Instead, it has a bunch of predefined variables, and users can only use those. This means that, to "readMetadata", the compiler must know which are these variables names so that it knows if it would fail when you reference a parameters. If it exists in that list nothing happens, but if it doesn't, it should fail with a "variable not declared".

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes that's what i expected but the compiler fails with a "messages variable not declared" in this document, why?

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The variable is declared, just not assigned a value yet

Copy link
Contributor

Choose a reason for hiding this comment

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

well, if withParameters contains messages, that's a bug in the compiler then 😅

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

talked offline, will fix it in the next pr

@@ -50,6 +51,10 @@ export default class Transaction {
* https://github.com/rails/rails/blob/main/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L769.
*/
static toResultError(error: unknown): ErrorResult<Error> {
if (env.NODE_ENV === 'development') {
console.error(error)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

make our lives easier

const result = await query

return Result.ok(result)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

pagination very needed here since we expect 10s of thousands of logs

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

hmm seems like very low level no? I don't want to reimplement the findAll query, just add some pagination to it

Copy link
Contributor

Choose a reason for hiding this comment

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

What do you mean? Is the official way of doing pagination in drizzle

Copy link
Collaborator Author

@geclos geclos Sep 5, 2024

Choose a reason for hiding this comment

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

no not talking about drizzle's api saying that if i already have the find and findall methods implementing in repositories i don't want to call another method to have the same but paginated, i just wanna indicate pagination as an options of those methods.

I will use page and pageSize instead of limit and offset though, I think it makes more sense, will do in the next PR

}

if (opts.offset !== undefined) {
// @ts-expect-error
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

since this is an abstract class implementing operations over a query that is defined by the children classes typescript has difficulties understanding the types, adding a bit of technical debt here in favour of moving forward towards the MVP

Copy link
Contributor

Choose a reason for hiding this comment

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

const inputCost = (inputCostPer1MToken * (inputTokens ?? 0)) / 1_000_000
const outputCost = (outputCostPer1MToken * (outputTokens ?? 0)) / 1_000_000
const inputCost =
(inputCostPer1MToken * (isNaN(inputTokens) ? 0 : inputTokens)) / 1_000_000
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this was a bug, vercel's ai can return NaN in some token usage for some providers. Probably a bug on their end but regardless we have to defend ourselves.

}: ModalProps) {
return (
<Dialog open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>
<DialogContent className='sm:max-w-modal'>
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this class wasn't getting applied because DialogContent was doing nothing with the prop className

@geclos geclos force-pushed the feature/evaluations_playground branch from dea4ce5 to 6bd65c2 Compare September 5, 2024 07:01
@geclos geclos marked this pull request as ready for review September 5, 2024 07:01
@geclos geclos force-pushed the feature/evaluations_playground branch 2 times, most recently from 1c7dda6 to bff38e0 Compare September 5, 2024 07:05
Comment on lines +75 to +87
useEffect(() => {
if (!metadata) return

// Remove only inputs that are no longer in the metadata, and add new ones
// Leave existing inputs as they are
setInputs(
Object.fromEntries(
Array.from(metadata.parameters).map((param) => {
if (param in inputs) return [param, inputs[param]!]

return [param, { value: '', type: 'input' }]
}),
),
)
}, [metadata])
Copy link
Contributor

Choose a reason for hiding this comment

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

There cannot be "new inputs". Evaluation only have the default predefined parameters that are extracted from a log.

Copy link
Collaborator Author

@geclos geclos Sep 5, 2024

Choose a reason for hiding this comment

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

hmm but the user can edit the evaluation prompt and remove the predefined parameters and add them back in, no? Nothing prevents me from editing the text on the left here

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

hmm weird ux imo, I'd rather show them a message telling them they have to include the messages variable if it's not present in the document, rather than showing an input for a variable that they have removed from the document

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, but the parameters always exist, wether you use them in the prompt or not. It is not like Documents, where ONLY when you reference a variable in the code a new parameter is created. In this case, users must only reference variables from a list of predefined variables, which are filled with data automatically from logs. I think we should always display this list to the user, so they’re aware of the parameters they have access to, even if they’re not currently using them in their code.

(resending this message, this was removed by accident)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

but if they don't use it in the document they won't have an effect at all when you run the prompt no? it's just weird to have an input for a variable that won't have any usage in the document. I understand that internally they exist in the state of the compiler when running the document, but that's not relevant to the user. It's better to tell the user "hey, remember to add the messages variable to your document" rather than just showing an input that has no effect on the evaluation

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we shouldn't display it as a bunch of inputs. We could just display a "log" there, with the ability to modify it.

@geclos geclos force-pushed the feature/evaluations_playground branch 2 times, most recently from f9bf84c to 34f1c7e Compare September 5, 2024 07:09
@geclos geclos force-pushed the feature/evaluations_playground branch from 34f1c7e to 48fc82c Compare September 5, 2024 07:30
default:
return 'default'
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Classic hash cc @ferranete

Modal to import logs while testing the evaluation in the editor
@geclos geclos force-pushed the feature/evaluations_playground branch from 48fc82c to 1db6b6d Compare September 5, 2024 07:39
@geclos geclos merged commit 6391a0d into main Sep 5, 2024
3 checks passed
@geclos geclos deleted the feature/evaluations_playground branch September 5, 2024 08:05
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.

3 participants