Skip to content

Commit

Permalink
New: Helicone Prompt Editor (#3153)
Browse files Browse the repository at this point in the history
* WIP: First

* Refactor: web/utlis -> web/utils naming

* Upgrade: "opeanai" + installed "change-case-all"

* WIP: 2, difficulties with pages / app directory

* WIP: 3, llm.ts api route, generate lib

* WIP: 4, Respons panel working

* Fix: new imports

* Fix: x-cancel try

* Misc: Updated styles

* New:  user-defined-id jawn api route / helpers / misc

* Upgrade: bundle-analyzer on par with next, tailwind latest

* WIP 5: Most of remaining prompt-editor functionality

* Fix: eslint errors

* Fix: eslint warnings

* Fix: updateState() race conditions with new function form

* Update: Further usage of new updateState functionality

* Update: Dialog for "Import from code" snippet

* Update: Disabled action buttons when not created from ui

* moving inputs to metadata

* added question mark operator to provider

* Fix: PromptManager metadata jsonb casting

* Misc: Clean up

* Update: New models from openrouter

* Misc: Formatting

* added input from prod in prompts

* added create experiment from prompt

* Update: Deploy dialog

* Misc: Deleted old server actions

---------

Co-authored-by: Justin <[email protected]>
  • Loading branch information
tinomarques and chitalian authored Jan 22, 2025
1 parent a69b6cd commit b4fbb17
Show file tree
Hide file tree
Showing 75 changed files with 6,135 additions and 1,877 deletions.
25 changes: 25 additions & 0 deletions bifrost/lib/clients/jawnTypes/private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ export interface paths {
"/v1/prompt/create": {
post: operations["CreatePrompt"];
};
"/v1/prompt/{promptId}/user-defined-id": {
patch: operations["UpdatePromptUserDefinedId"];
};
"/v1/prompt/version/{promptVersionId}/edit-label": {
post: operations["EditPromptVersionLabel"];
};
Expand Down Expand Up @@ -2800,6 +2803,28 @@ export interface operations {
};
};
};
UpdatePromptUserDefinedId: {
parameters: {
path: {
promptId: string;
};
};
requestBody: {
content: {
"application/json": {
userDefinedId: string;
};
};
};
responses: {
/** @description Ok */
200: {
content: {
"application/json": components["schemas"]["Result_null.string_"];
};
};
};
};
EditPromptVersionLabel: {
parameters: {
path: {
Expand Down
25 changes: 25 additions & 0 deletions bifrost/lib/clients/jawnTypes/public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ export interface paths {
"/v1/prompt/create": {
post: operations["CreatePrompt"];
};
"/v1/prompt/{promptId}/user-defined-id": {
patch: operations["UpdatePromptUserDefinedId"];
};
"/v1/prompt/version/{promptVersionId}/edit-label": {
post: operations["EditPromptVersionLabel"];
};
Expand Down Expand Up @@ -2828,6 +2831,28 @@ export interface operations {
};
};
};
UpdatePromptUserDefinedId: {
parameters: {
path: {
promptId: string;
};
};
requestBody: {
content: {
"application/json": {
userDefinedId: string;
};
};
};
responses: {
/** @description Ok */
200: {
content: {
"application/json": components["schemas"]["Result_null.string_"];
};
};
};
};
EditPromptVersionLabel: {
parameters: {
path: {
Expand Down
53 changes: 53 additions & 0 deletions docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -8690,6 +8690,59 @@
}
}
},
"/v1/prompt/{promptId}/user-defined-id": {
"patch": {
"operationId": "UpdatePromptUserDefinedId",
"responses": {
"200": {
"description": "Ok",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Result_null.string_"
}
}
}
}
},
"tags": [
"Prompt"
],
"security": [
{
"api_key": []
}
],
"parameters": [
{
"in": "path",
"name": "promptId",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"properties": {
"userDefinedId": {
"type": "string"
}
},
"required": [
"userDefinedId"
],
"type": "object"
}
}
}
}
}
},
"/v1/prompt/version/{promptVersionId}/edit-label": {
"post": {
"operationId": "EditPromptVersionLabel",
Expand Down
20 changes: 20 additions & 0 deletions valhalla/jawn/src/controllers/public/promptController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Route,
Security,
Tags,
Patch,
} from "tsoa";
import { Result, resultMap } from "../../lib/shared/result";
import {
Expand Down Expand Up @@ -231,6 +232,25 @@ export class PromptController extends Controller {
return result;
}

@Patch("{promptId}/user-defined-id")
public async updatePromptUserDefinedId(
@Request() request: JawnAuthenticatedRequest,
@Path() promptId: string,
@Body() requestBody: { userDefinedId: string }
): Promise<Result<null, string>> {
const promptManager = new PromptManager(request.authParams);
const result = await promptManager.updatePromptUserDefinedId(
promptId,
requestBody.userDefinedId
);
if (result.error) {
this.setStatus(500);
} else {
this.setStatus(200);
}
return result;
}

@Post("version/{promptVersionId}/edit-label")
public async editPromptVersionLabel(
@Body()
Expand Down
57 changes: 49 additions & 8 deletions valhalla/jawn/src/managers/prompt/PromptManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export class PromptManager extends BaseManager {
LIMIT 1
)
END,
$6,
$6::jsonb,
$7::uuid,
ppv.id,
CASE
Expand All @@ -171,6 +171,7 @@ export class PromptManager extends BaseManager {
helicone_template,
prompt_v2,
model,
metadata,
experiment_id;
`,
[
Expand All @@ -185,7 +186,7 @@ export class PromptManager extends BaseManager {
]
);

return resultMap(result, (data) => data[0]);
return resultMap(result, data => data[0]);
}

async editPromptVersionTemplate(
Expand Down Expand Up @@ -219,7 +220,7 @@ export class PromptManager extends BaseManager {
? params.heliconeTemplate
: JSON.stringify(params.heliconeTemplate)
).matchAll(/<helicone-prompt-input key=\\"(\w+)\\" \/>/g)
).map((match) => match[1]);
).map(match => match[1]);

const existingExperimentInputKeys = await supabaseServer.client
.from("experiment_v3")
Expand Down Expand Up @@ -248,7 +249,7 @@ export class PromptManager extends BaseManager {
),
]);

if (res.some((r) => r.error)) {
if (res.some(r => r.error)) {
return err("Failed to update experiment input keys");
}

Expand Down Expand Up @@ -287,7 +288,7 @@ export class PromptManager extends BaseManager {
[params.label, promptVersionId, this.authParams.organizationId]
);

return resultMap(result, (data) => data[0]);
return resultMap(result, data => data[0]);
}

async promotePromptVersionToProduction(
Expand Down Expand Up @@ -677,7 +678,7 @@ export class PromptManager extends BaseManager {
[this.authParams.organizationId, promptId]
);

return resultMap(result, (data) => data[0]);
return resultMap(result, data => data[0]);
}

async getPromptVersion(params: {
Expand Down Expand Up @@ -807,6 +808,46 @@ export class PromptManager extends BaseManager {
return ok(null);
}

async updatePromptUserDefinedId(
promptId: string,
newUserDefinedId: string
): Promise<Result<null, string>> {
// First check if the new ID already exists
const existingPrompt = await dbExecute<{
id: string;
}>(
`
SELECT id FROM prompt_v2
WHERE user_defined_id = $1
AND organization = $2
AND soft_delete = false
`,
[newUserDefinedId, this.authParams.organizationId]
);

if (existingPrompt.data && existingPrompt.data.length > 0) {
return err(`Prompt with name ${newUserDefinedId} already exists`);
}

// Update the prompt's user_defined_id
const result = await dbExecute(
`
UPDATE prompt_v2
SET user_defined_id = $1
WHERE id = $2
AND organization = $3
AND soft_delete = false
`,
[newUserDefinedId, promptId, this.authParams.organizationId]
);

if (result.error) {
return err(`Failed to update prompt user_defined_id: ${result.error}`);
}

return ok(null);
}

public getHeliconeTemplateKeys(template: string | object): string[] {
try {
// Convert to string if it's an object
Expand All @@ -820,7 +861,7 @@ export class PromptManager extends BaseManager {
const regex = /<helicone-prompt-input key="([^"]+)"\s*\/>/g;
const matches = str.match(regex);
return matches
? matches.map((match) =>
? matches.map(match =>
match.replace(/<helicone-prompt-input key="|"\s*\/>/g, "")
)
: [];
Expand All @@ -834,7 +875,7 @@ export class PromptManager extends BaseManager {
if (typeof value === "string") {
keys.push(...findKeys(value));
} else if (Array.isArray(value)) {
value.forEach((item) => {
value.forEach(item => {
if (typeof item === "string") {
keys.push(...findKeys(item));
} else if (typeof item === "object") {
Expand Down
33 changes: 33 additions & 0 deletions valhalla/jawn/src/tsoa-build/private/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3255,6 +3255,39 @@ export function RegisterRoutes(app: Router) {
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
app.patch('/v1/prompt/:promptId/user-defined-id',
authenticateMiddleware([{"api_key":[]}]),
...(fetchMiddlewares<RequestHandler>(PromptController)),
...(fetchMiddlewares<RequestHandler>(PromptController.prototype.updatePromptUserDefinedId)),

async function PromptController_updatePromptUserDefinedId(request: ExRequest, response: ExResponse, next: any) {
const args: Record<string, TsoaRoute.ParameterSchema> = {
request: {"in":"request","name":"request","required":true,"dataType":"object"},
promptId: {"in":"path","name":"promptId","required":true,"dataType":"string"},
requestBody: {"in":"body","name":"requestBody","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"userDefinedId":{"dataType":"string","required":true}}},
};

// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa

let validatedArgs: any[] = [];
try {
validatedArgs = templateService.getValidatedArgs({ args, request, response });

const controller = new PromptController();

await templateService.apiHandler({
methodName: 'updatePromptUserDefinedId',
controller,
response,
next,
validatedArgs,
successStatus: undefined,
});
} catch (err) {
return next(err);
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
app.post('/v1/prompt/version/:promptVersionId/edit-label',
authenticateMiddleware([{"api_key":[]}]),
...(fetchMiddlewares<RequestHandler>(PromptController)),
Expand Down
53 changes: 53 additions & 0 deletions valhalla/jawn/src/tsoa-build/private/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -7413,6 +7413,59 @@
}
}
},
"/v1/prompt/{promptId}/user-defined-id": {
"patch": {
"operationId": "UpdatePromptUserDefinedId",
"responses": {
"200": {
"description": "Ok",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Result_null.string_"
}
}
}
}
},
"tags": [
"Prompt"
],
"security": [
{
"api_key": []
}
],
"parameters": [
{
"in": "path",
"name": "promptId",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"properties": {
"userDefinedId": {
"type": "string"
}
},
"required": [
"userDefinedId"
],
"type": "object"
}
}
}
}
}
},
"/v1/prompt/version/{promptVersionId}/edit-label": {
"post": {
"operationId": "EditPromptVersionLabel",
Expand Down
Loading

0 comments on commit b4fbb17

Please sign in to comment.