Add initial client lib

This commit is contained in:
David Corbitt
2023-07-30 00:18:24 -07:00
parent 2c65ad0c8f
commit 955716eb77
40 changed files with 2436 additions and 52 deletions

4
.gitignore vendored
View File

@@ -42,3 +42,7 @@
# typescript # typescript
/app/*.tsbuildinfo /app/*.tsbuildinfo
# Client Libs files
/client-libs/js/node_modules

View File

@@ -13,6 +13,7 @@ declare module "nextjs-routes" {
export type Route = export type Route =
| StaticRoute<"/account/signin"> | StaticRoute<"/account/signin">
| DynamicRoute<"/api/auth/[...nextauth]", { "nextauth": string[] }> | DynamicRoute<"/api/auth/[...nextauth]", { "nextauth": string[] }>
| StaticRoute<"/api/openapi">
| DynamicRoute<"/api/trpc/[trpc]", { "trpc": string }> | DynamicRoute<"/api/trpc/[trpc]", { "trpc": string }>
| DynamicRoute<"/experiments/[id]", { "id": string }> | DynamicRoute<"/experiments/[id]", { "id": string }>
| StaticRoute<"/experiments"> | StaticRoute<"/experiments">

7
app/openapitools.json Normal file
View File

@@ -0,0 +1,7 @@
{
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "6.6.0"
}
}

View File

@@ -16,7 +16,7 @@
"postinstall": "prisma generate", "postinstall": "prisma generate",
"lint": "next lint", "lint": "next lint",
"start": "next start", "start": "next start",
"codegen": "tsx src/codegen/export-openai-types.ts", "codegen": "tsx src/codegen/export-client-types.ts",
"seed": "tsx prisma/seed.ts", "seed": "tsx prisma/seed.ts",
"check": "concurrently 'pnpm lint' 'pnpm tsc' 'pnpm prettier . --check'" "check": "concurrently 'pnpm lint' 'pnpm tsc' 'pnpm prettier . --check'"
}, },
@@ -79,6 +79,7 @@
"socket.io": "^4.7.1", "socket.io": "^4.7.1",
"socket.io-client": "^4.7.1", "socket.io-client": "^4.7.1",
"superjson": "1.12.2", "superjson": "1.12.2",
"trpc-openapi": "^1.2.0",
"tsx": "^3.12.7", "tsx": "^3.12.7",
"type-fest": "^4.0.0", "type-fest": "^4.0.0",
"use-query-params": "^2.2.1", "use-query-params": "^2.2.1",

105
app/pnpm-lock.yaml generated
View File

@@ -1,4 +1,4 @@
lockfileVersion: '6.1' lockfileVersion: '6.0'
settings: settings:
autoInstallPeers: true autoInstallPeers: true
@@ -179,6 +179,9 @@ dependencies:
superjson: superjson:
specifier: 1.12.2 specifier: 1.12.2
version: 1.12.2 version: 1.12.2
trpc-openapi:
specifier: ^1.2.0
version: 1.2.0(@trpc/server@10.26.0)(zod@3.21.4)
tsx: tsx:
specifier: ^3.12.7 specifier: ^3.12.7
version: 3.12.7 version: 3.12.7
@@ -3861,6 +3864,15 @@ packages:
wrap-ansi: 7.0.0 wrap-ansi: 7.0.0
dev: false dev: false
/co-body@6.1.0:
resolution: {integrity: sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==}
dependencies:
inflation: 2.0.0
qs: 6.11.2
raw-body: 2.5.1
type-is: 1.6.18
dev: false
/color-convert@1.9.3: /color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies: dependencies:
@@ -3935,6 +3947,10 @@ packages:
/convert-source-map@1.9.0: /convert-source-map@1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
/cookie-es@1.0.0:
resolution: {integrity: sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ==}
dev: false
/cookie-signature@1.0.6: /cookie-signature@1.0.6:
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
dev: false dev: false
@@ -4137,11 +4153,20 @@ packages:
has-property-descriptors: 1.0.0 has-property-descriptors: 1.0.0
object-keys: 1.1.1 object-keys: 1.1.1
/defu@6.1.2:
resolution: {integrity: sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ==}
dev: false
/delayed-stream@1.0.0: /delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
dev: false dev: false
/depd@1.1.2:
resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
engines: {node: '>= 0.6'}
dev: false
/depd@2.0.0: /depd@2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -4152,6 +4177,10 @@ packages:
engines: {node: '>=6'} engines: {node: '>=6'}
dev: true dev: true
/destr@2.0.0:
resolution: {integrity: sha512-FJ9RDpf3GicEBvzI3jxc2XhHzbqD8p4ANw/1kPsFBfTvP1b7Gn/Lg1vO7R9J4IVgoMbyUmFrFGZafJ1hPZpvlg==}
dev: false
/destroy@1.2.0: /destroy@1.2.0:
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -5273,6 +5302,18 @@ packages:
- pg-native - pg-native
dev: false dev: false
/h3@1.7.1:
resolution: {integrity: sha512-A9V2NEDNHet7v1gCg7CMwerSigLi0SRbhTy7C3lGb0N4YKIpPmLDjedTUopqp4dnn7COHfqUjjaz3zbtz4QduA==}
dependencies:
cookie-es: 1.0.0
defu: 6.1.2
destr: 2.0.0
iron-webcrypto: 0.7.1
radix3: 1.0.1
ufo: 1.1.2
uncrypto: 0.1.3
dev: false
/has-bigints@1.0.2: /has-bigints@1.0.2:
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
dev: true dev: true
@@ -5400,6 +5441,11 @@ packages:
engines: {node: '>=0.8.19'} engines: {node: '>=0.8.19'}
dev: true dev: true
/inflation@2.0.0:
resolution: {integrity: sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==}
engines: {node: '>= 0.8.0'}
dev: false
/inflight@1.0.6: /inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
dependencies: dependencies:
@@ -5429,6 +5475,10 @@ packages:
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
dev: false dev: false
/iron-webcrypto@0.7.1:
resolution: {integrity: sha512-K/UmlEhPCPXEHV5hAtH5C0tI5JnFuOrv4yO/j7ODPl3HaiiHBLbOLTde+ieUaAyfCATe4LoAnclyF+hmSCOVmQ==}
dev: false
/is-alphabetical@1.0.4: /is-alphabetical@1.0.4:
resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==}
dev: false dev: false
@@ -6161,6 +6211,22 @@ packages:
whatwg-url: 5.0.0 whatwg-url: 5.0.0
dev: false dev: false
/node-mocks-http@1.12.2:
resolution: {integrity: sha512-xhWwC0dh35R9rf0j3bRZXuISXdHxxtMx0ywZQBwjrg3yl7KpRETzogfeCamUIjltpn0Fxvs/ZhGJul1vPLrdJQ==}
engines: {node: '>=0.6'}
dependencies:
accepts: 1.3.8
content-disposition: 0.5.4
depd: 1.1.2
fresh: 0.5.2
merge-descriptors: 1.0.1
methods: 1.1.2
mime: 1.6.0
parseurl: 1.3.3
range-parser: 1.2.1
type-is: 1.6.18
dev: false
/node-releases@2.0.13: /node-releases@2.0.13:
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
@@ -6322,6 +6388,10 @@ packages:
- supports-color - supports-color
dev: false dev: false
/openapi-types@12.1.3:
resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
dev: false
/openapi-typescript@5.4.1: /openapi-typescript@5.4.1:
resolution: {integrity: sha512-AGB2QiZPz4rE7zIwV3dRHtoUC/CWHhUjuzGXvtmMQN2AFV8xCTLKcZUHLcdPQmt/83i22nRE7+TxXOXkK+gf4Q==} resolution: {integrity: sha512-AGB2QiZPz4rE7zIwV3dRHtoUC/CWHhUjuzGXvtmMQN2AFV8xCTLKcZUHLcdPQmt/83i22nRE7+TxXOXkK+gf4Q==}
engines: {node: '>= 14.0.0'} engines: {node: '>= 14.0.0'}
@@ -6745,6 +6815,10 @@ packages:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true dev: true
/radix3@1.0.1:
resolution: {integrity: sha512-y+AcwZ3HcUIGc9zGsNVf5+BY/LxL+z+4h4J3/pp8jxSmy1STaCocPS3qrj4tA5ehUSzqtqK+0Aygvz/r/8vy4g==}
dev: false
/randombytes@2.1.0: /randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
dependencies: dependencies:
@@ -7645,6 +7719,22 @@ packages:
hasBin: true hasBin: true
dev: false dev: false
/trpc-openapi@1.2.0(@trpc/server@10.26.0)(zod@3.21.4):
resolution: {integrity: sha512-pfYoCd/3KYXWXvUPZBKJw455OOwngKN/6SIcj7Yit19OMLJ+8yVZkEvGEeg5wUSwfsiTdRsKuvqkRPXVSwV7ew==}
peerDependencies:
'@trpc/server': ^10.0.0
zod: ^3.14.4
dependencies:
'@trpc/server': 10.26.0
co-body: 6.1.0
h3: 1.7.1
lodash.clonedeep: 4.5.0
node-mocks-http: 1.12.2
openapi-types: 12.1.3
zod: 3.21.4
zod-to-json-schema: 3.21.4(zod@3.21.4)
dev: false
/tsconfck@2.1.2(typescript@5.0.4): /tsconfck@2.1.2(typescript@5.0.4):
resolution: {integrity: sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==} resolution: {integrity: sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==}
engines: {node: ^14.13.1 || ^16 || >=18} engines: {node: ^14.13.1 || ^16 || >=18}
@@ -7782,7 +7872,6 @@ packages:
/ufo@1.1.2: /ufo@1.1.2:
resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==} resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==}
dev: true
/unbox-primitive@1.0.2: /unbox-primitive@1.0.2:
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
@@ -7793,6 +7882,10 @@ packages:
which-boxed-primitive: 1.0.2 which-boxed-primitive: 1.0.2
dev: true dev: true
/uncrypto@0.1.3:
resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
dev: false
/undici@5.22.1: /undici@5.22.1:
resolution: {integrity: sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==} resolution: {integrity: sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==}
engines: {node: '>=14.0'} engines: {node: '>=14.0'}
@@ -8305,6 +8398,14 @@ packages:
engines: {node: '>=12.20'} engines: {node: '>=12.20'}
dev: true dev: true
/zod-to-json-schema@3.21.4(zod@3.21.4):
resolution: {integrity: sha512-fjUZh4nQ1s6HMccgIeE0VP4QG/YRGPmyjO9sAh890aQKPEk3nqbfUXhMFaC+Dr5KvYBm8BCyvfpZf2jY9aGSsw==}
peerDependencies:
zod: ^3.21.4
dependencies:
zod: 3.21.4
dev: false
/zod@3.21.4: /zod@3.21.4:
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
dev: false dev: false

View File

@@ -0,0 +1,64 @@
-- AlterTable
ALTER TABLE "Experiment" ADD COLUMN "dataFlowId" UUID;
-- AlterTable
ALTER TABLE "ModelResponse" ADD COLUMN "loggedCallId" UUID,
ALTER COLUMN "scenarioVariantCellId" DROP NOT NULL;
-- CreateTable
CREATE TABLE "LoggedCall" (
"id" UUID NOT NULL,
"promptFunctionHash" TEXT NOT NULL,
"promptFunction" TEXT NOT NULL,
"prompt" JSONB NOT NULL,
"responsePayload" JSONB,
"scenarioVariables" JSONB NOT NULL,
"model" TEXT NOT NULL,
"modelProvider" TEXT NOT NULL,
"dataFlowId" UUID NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "LoggedCall_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "DataFlow" (
"id" UUID NOT NULL,
"label" TEXT NOT NULL,
"organizationId" UUID NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "DataFlow_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ApiKey" (
"id" UUID NOT NULL,
"name" TEXT NOT NULL,
"key" TEXT NOT NULL,
"organizationId" UUID NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "ApiKey_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "ApiKey_key_key" ON "ApiKey"("key");
-- AddForeignKey
ALTER TABLE "Experiment" ADD CONSTRAINT "Experiment_dataFlowId_fkey" FOREIGN KEY ("dataFlowId") REFERENCES "DataFlow"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ModelResponse" ADD CONSTRAINT "ModelResponse_loggedCallId_fkey" FOREIGN KEY ("loggedCallId") REFERENCES "LoggedCall"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoggedCall" ADD CONSTRAINT "LoggedCall_dataFlowId_fkey" FOREIGN KEY ("dataFlowId") REFERENCES "DataFlow"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "DataFlow" ADD CONSTRAINT "DataFlow_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ApiKey" ADD CONSTRAINT "ApiKey_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -19,6 +19,9 @@ model Experiment {
organizationId String @db.Uuid organizationId String @db.Uuid
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade) organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
dataFlowId String? @db.Uuid
dataFlow DataFlow? @relation(fields: [dataFlowId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
@@ -127,10 +130,13 @@ model ModelResponse {
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
scenarioVariantCellId String @db.Uuid scenarioVariantCellId String? @db.Uuid
scenarioVariantCell ScenarioVariantCell @relation(fields: [scenarioVariantCellId], references: [id], onDelete: Cascade) scenarioVariantCell ScenarioVariantCell? @relation(fields: [scenarioVariantCellId], references: [id], onDelete: Cascade)
outputEvaluations OutputEvaluation[] outputEvaluations OutputEvaluation[]
loggedCallId String? @db.Uuid
loggedCall LoggedCall? @relation(fields: [loggedCallId], references: [id], onDelete: Cascade)
@@index([inputHash]) @@index([inputHash])
} }
@@ -174,10 +180,57 @@ model OutputEvaluation {
@@unique([modelResponseId, evaluationId]) @@unique([modelResponseId, evaluationId])
} }
model LoggedCall {
id String @id @default(uuid()) @db.Uuid
promptFunctionHash String
promptFunction String
prompt Json
responsePayload Json?
scenarioVariables Json
model String
modelProvider String
dataFlowId String @db.Uuid
dataFlow DataFlow @relation(fields: [dataFlowId], references: [id], onDelete: Cascade)
modelResponse ModelResponse[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model DataFlow {
id String @id @default(uuid()) @db.Uuid
label String
experiments Experiment[]
loggedCalls LoggedCall[]
organizationId String @db.Uuid
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ApiKey {
id String @id @default(uuid()) @db.Uuid
name String
key String @unique
organizationId String @db.Uuid
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Organization { model Organization {
id String @id @default(uuid()) @db.Uuid id String @id @default(uuid()) @db.Uuid
personalOrgUserId String? @unique @db.Uuid personalOrgUserId String? @unique @db.Uuid
PersonalOrgUser User? @relation(fields: [personalOrgUserId], references: [id], onDelete: Cascade) personalOrgUser User? @relation(fields: [personalOrgUserId], references: [id], onDelete: Cascade)
apiKeys ApiKey[]
dataFlows DataFlow[]
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt

View File

@@ -0,0 +1,42 @@
import "dotenv/config";
import { openApiDocument } from "~/pages/api/openapi.json";
import fs from "fs";
import path from "path";
import { execSync } from "child_process";
import { generatePromptTypes } from "~/modelProviders/generatePromptTypes";
console.log("Exporting public OpenAPI schema to client-libs/schema.json");
const executionDir = import.meta.url.replace("file://", "");
const schemaPath = path.join(
path.dirname(executionDir),
"../../../client-libs/schema.json"
);
console.log("Exporting schema");
fs.writeFileSync(schemaPath, JSON.stringify(openApiDocument, null, 2), "utf-8");
console.log("Generating Typescript client");
const tsClientPath = path.join(
path.dirname(executionDir),
"../../../client-libs/js/codegen"
);
fs.rmSync(tsClientPath, { recursive: true, force: true });
execSync(
`pnpm dlx @openapitools/openapi-generator-cli generate -i "${schemaPath}" -g typescript-axios -o "${tsClientPath}"`,
{
stdio: "inherit",
}
);
const promptTypes = await generatePromptTypes();
const promptTypesPath = path.join(tsClientPath, "promptTypes.ts");
console.log(`Writing promptTypes to ${promptTypesPath}`);
fs.writeFileSync(promptTypesPath, promptTypes, "utf-8");
console.log("Done!");

View File

@@ -0,0 +1,41 @@
import { type JSONSchema4Object } from "json-schema";
import modelProviders from "./modelProviders";
import { compile } from "json-schema-to-typescript";
import dedent from "dedent";
export const declarePromptTypes = async () => {
const promptTypes = (await generatePromptTypes()).replace(
/export interface PromptTypes/g,
"interface PromptTypes",
);
return dedent`
${promptTypes}
declare function definePrompt<T extends keyof PromptTypes>(modelProvider: T, input: PromptTypes[T])
`;
};
export const generatePromptTypes = async () => {
const combinedSchema = {
type: "object",
properties: {} as Record<string, JSONSchema4Object>,
};
Object.entries(modelProviders).forEach(([id, provider]) => {
combinedSchema.properties[id] = provider.inputSchema;
});
Object.entries(modelProviders).forEach(([id, provider]) => {
combinedSchema.properties[id] = provider.inputSchema;
});
return await compile(combinedSchema as JSONSchema4Object, "PromptTypes", {
additionalProperties: false,
bannerComment: dedent`
/**
* This type map defines the input types for each model provider.
*/
`,
});
};

View File

@@ -1,36 +0,0 @@
import { type JSONSchema4Object } from "json-schema";
import modelProviders from "./modelProviders";
import { compile } from "json-schema-to-typescript";
import dedent from "dedent";
export default async function generateTypes() {
const combinedSchema = {
type: "object",
properties: {} as Record<string, JSONSchema4Object>,
};
Object.entries(modelProviders).forEach(([id, provider]) => {
combinedSchema.properties[id] = provider.inputSchema;
});
Object.entries(modelProviders).forEach(([id, provider]) => {
combinedSchema.properties[id] = provider.inputSchema;
});
const promptTypes = (
await compile(combinedSchema as JSONSchema4Object, "PromptTypes", {
additionalProperties: false,
bannerComment: dedent`
/**
* This type map defines the input types for each model provider.
*/
`,
})
).replace(/export interface PromptTypes/g, "interface PromptTypes");
return dedent`
${promptTypes}
declare function definePrompt<T extends keyof PromptTypes>(modelProvider: T, input: PromptTypes[T])
`;
}

View File

@@ -0,0 +1,16 @@
import { type NextApiRequest, type NextApiResponse } from "next";
import { generateOpenApiDocument } from "trpc-openapi";
import { appRouter } from "~/server/api/root.router";
export const openApiDocument = generateOpenApiDocument(appRouter, {
title: "OpenPipe API",
description: "The public API for reporting API calls to OpenPipe",
version: "0.1.0",
baseUrl: "https://app.openpipe.ai/api",
});
// Respond with our OpenAPI schema
const handler = (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).send(openApiDocument);
};
export default handler;

View File

@@ -5,6 +5,7 @@ import { scenariosRouter } from "./routers/scenarios.router";
import { scenarioVariantCellsRouter } from "./routers/scenarioVariantCells.router"; import { scenarioVariantCellsRouter } from "./routers/scenarioVariantCells.router";
import { templateVarsRouter } from "./routers/templateVariables.router"; import { templateVarsRouter } from "./routers/templateVariables.router";
import { evaluationsRouter } from "./routers/evaluations.router"; import { evaluationsRouter } from "./routers/evaluations.router";
import { externalApiRouter } from "./routers/externalApi.router";
/** /**
* This is the primary router for your server. * This is the primary router for your server.
@@ -18,6 +19,7 @@ export const appRouter = createTRPCRouter({
scenarioVariantCells: scenarioVariantCellsRouter, scenarioVariantCells: scenarioVariantCellsRouter,
templateVars: templateVarsRouter, templateVars: templateVarsRouter,
evaluations: evaluationsRouter, evaluations: evaluationsRouter,
externalApi: externalApiRouter,
}); });
// export type definition of API // export type definition of API

View File

@@ -0,0 +1,92 @@
import { z } from "zod";
import { createTRPCRouter, protectedProcedure, publicProcedure } from "~/server/api/trpc";
import { prisma } from "~/server/db";
import {
requireCanAccessDataFlow,
requireNothing,
} from "~/utils/accessControl";
import userOrg from "~/server/utils/userOrg";
export const dataFlowRouter = createTRPCRouter({
list: protectedProcedure.query(async ({ ctx }) => {
// Anyone can list data flows
requireNothing(ctx);
const dataFlows = await prisma.dataFlow.findMany({
where: {
organization: {
organizationUsers: {
some: { userId: ctx.session.user.id },
},
},
},
orderBy: {
createdAt: "desc",
},
});
// TODO: look for cleaner way to do this. Maybe aggregate?
const dataFlowsWithCounts = await Promise.all(
dataFlows.map(async (dataFlow) => {
const loggedCallCount = await prisma.loggedCall.count({
where: {
dataFlowId: dataFlow.id,
},
});
return {
...dataFlow,
loggedCallCount,
};
}),
);
return dataFlowsWithCounts;
}),
get: publicProcedure.input(z.object({ id: z.string() })).query(async ({ input, ctx }) => {
await requireCanAccessDataFlow(input.id, ctx);
return await prisma.dataFlow.findFirstOrThrow({
where: { id: input.id },
});
}),
create: protectedProcedure.input(z.object({})).mutation(async ({ ctx }) => {
// Anyone can create a data flow
requireNothing(ctx);
return await prisma.dataFlow.create({
data: {
label: `Untitled Data Flow`,
organizationId: (await userOrg(ctx.session.user.id)).id,
},
});
}),
update: protectedProcedure
.input(z.object({ id: z.string(), updates: z.object({ label: z.string() }) }))
.mutation(async ({ input, ctx }) => {
await requireCanAccessDataFlow(input.id, ctx);
return await prisma.dataFlow.update({
where: {
id: input.id,
},
data: {
label: input.updates.label,
},
});
}),
delete: protectedProcedure
.input(z.object({ id: z.string() }))
.mutation(async ({ input, ctx }) => {
await requireCanAccessDataFlow(input.id, ctx);
await prisma.dataFlow.delete({
where: {
id: input.id,
},
});
}),
});

View File

@@ -12,7 +12,7 @@ import {
requireNothing, requireNothing,
} from "~/utils/accessControl"; } from "~/utils/accessControl";
import userOrg from "~/server/utils/userOrg"; import userOrg from "~/server/utils/userOrg";
import generateTypes from "~/modelProviders/generateTypes"; import { declarePromptTypes } from "~/modelProviders/generatePromptTypes";
export const experimentsRouter = createTRPCRouter({ export const experimentsRouter = createTRPCRouter({
list: protectedProcedure.query(async ({ ctx }) => { list: protectedProcedure.query(async ({ ctx }) => {
@@ -383,6 +383,6 @@ export const experimentsRouter = createTRPCRouter({
// Keeping these on `experiment` for now because we might want to limit the // Keeping these on `experiment` for now because we might want to limit the
// providers based on your account/experiment // providers based on your account/experiment
promptTypes: publicProcedure.query(async () => { promptTypes: publicProcedure.query(async () => {
return await generateTypes(); return await declarePromptTypes();
}), }),
}); });

View File

@@ -0,0 +1,113 @@
import { type Prisma } from "@prisma/client";
import { type JsonObject } from "type-fest";
import { z } from "zod";
import modelProviders from "~/modelProviders/modelProviders";
import { type SupportedProvider } from "~/modelProviders/types";
import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";
import { prisma } from "~/server/db";
import hashSortedObject, { hashString } from "~/server/utils/hashSortedObject";
export const externalApiRouter = createTRPCRouter({
capturePrompt: publicProcedure
.meta({
openapi: {
method: "POST",
path: "/v1/capture-prompt",
description: "Capture a prompt with its variables call",
},
})
.input(
z.object({
apiKey: z.string().describe("API token for authentication"),
dataFlowId: z.string().describe("Data flow ID"),
promptFunction: z.string().describe("Prompt construction function"),
scenarioVariables: z.unknown().describe("Scenario variables as JSON"),
prompt: z.unknown().describe("Prompt object as JSON"),
model: z.string().describe("Model name"),
modelProvider: z.string().describe("Model provider"),
}),
)
.output(z.string())
.mutation(async ({ input }) => {
const apiKey = await prisma.apiKey.findUnique({
where: { key: input.apiKey },
});
if (!apiKey) {
throw new Error("Invalid API token");
}
const dataFlow = await prisma.dataFlow.findUnique({
where: { id: input.dataFlowId },
});
if (!dataFlow) {
throw new Error("Invalid data flow ID");
}
const loggedCall = await prisma.loggedCall.create({
data: {
dataFlowId: input.dataFlowId,
promptFunctionHash: hashString(input.promptFunction),
// Pass the constructor function and the parsed values here since
// we want to let the user change the constructor function for all scenarios
promptFunction: input.promptFunction,
scenarioVariables: input.scenarioVariables as Prisma.InputJsonValue,
model: input.model,
modelProvider: input.modelProvider,
prompt: input.prompt as Prisma.InputJsonValue,
},
});
return loggedCall.id;
}),
captureResponse: publicProcedure
.meta({
openapi: {
method: "POST",
path: "/v1/capture-response",
description: "Capture a response to a prompt",
},
})
.input(
z.object({
apiKey: z.string().describe("API token for authentication"),
loggedCallId: z.string().describe("Logged call ID"),
responsePayload: z.unknown().describe("JSON-encoded response payload"),
}),
)
.output(z.void())
.mutation(async ({ input }) => {
const apiKey = await prisma.apiKey.findUnique({
where: { key: input.apiKey },
});
if (!apiKey) {
throw new Error("Invalid API token");
}
const loggedCall = await prisma.loggedCall.findUnique({
where: { id: input.loggedCallId },
});
if (!loggedCall) {
throw new Error("Invalid call log ID");
}
await prisma.loggedCall.update({
where: { id: input.loggedCallId },
data: {
responsePayload: input.responsePayload as Prisma.InputJsonValue,
},
});
const modelProvider = modelProviders[loggedCall.modelProvider as SupportedProvider];
const inputHash = hashSortedObject(loggedCall.prompt as JsonObject);
await prisma.modelResponse.create({
data: {
inputHash,
loggedCallId: input.loggedCallId,
output: modelProvider.normalizeOutput(input.responsePayload),
// TODO: get more accurate time values
requestedAt: loggedCall.createdAt,
receivedAt: new Date(),
statusCode: 200,
},
});
}),
});

View File

@@ -0,0 +1,65 @@
import { z } from "zod";
import { createTRPCRouter, protectedProcedure, publicProcedure } from "~/server/api/trpc";
import { prisma } from "~/server/db";
import { requireCanAccessDataFlow } from "~/utils/accessControl";
export const loggedCallRouter = createTRPCRouter({
list: protectedProcedure
.input(z.object({ dataFlowId: z.string() }))
.query(async ({ input, ctx }) => {
await requireCanAccessDataFlow(input.dataFlowId, ctx);
return await prisma.loggedCall.findMany({
where: {
dataFlowId: input.dataFlowId,
},
include: {
modelResponse: true,
},
orderBy: {
createdAt: "desc",
},
});
}),
get: publicProcedure.input(z.object({ id: z.string() })).query(async ({ input, ctx }) => {
const loggedCall = await prisma.loggedCall.findFirst({
where: {
id: input.id,
},
include: {
modelResponse: true,
}
});
if (!loggedCall) {
throw new Error("Logged call not found");
}
await requireCanAccessDataFlow(loggedCall?.dataFlowId, ctx);
return loggedCall;
}),
delete: protectedProcedure
.input(z.object({ id: z.string() }))
.mutation(async ({ input, ctx }) => {
const loggedCall = await prisma.loggedCall.findFirst({
where: {
id: input.id,
},
});
if (!loggedCall) {
throw new Error("Logged call not found");
}
await requireCanAccessDataFlow(loggedCall?.dataFlowId, ctx);
await prisma.loggedCall.delete({
where: {
id: input.id,
},
});
}),
});

View File

@@ -11,6 +11,7 @@ import { initTRPC, TRPCError } from "@trpc/server";
import { type CreateNextContextOptions } from "@trpc/server/adapters/next"; import { type CreateNextContextOptions } from "@trpc/server/adapters/next";
import { type Session } from "next-auth"; import { type Session } from "next-auth";
import superjson from "superjson"; import superjson from "superjson";
import { OpenApiMeta } from "trpc-openapi";
import { ZodError } from "zod"; import { ZodError } from "zod";
import { getServerAuthSession } from "~/server/auth"; import { getServerAuthSession } from "~/server/auth";
import { prisma } from "~/server/db"; import { prisma } from "~/server/db";
@@ -75,7 +76,7 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => {
export type TRPCContext = Awaited<ReturnType<typeof createTRPCContext>>; export type TRPCContext = Awaited<ReturnType<typeof createTRPCContext>>;
const t = initTRPC.context<typeof createTRPCContext>().create({ const t = initTRPC.meta<OpenApiMeta>().context<typeof createTRPCContext>().create({
transformer: superjson, transformer: superjson,
errorFormatter({ shape, error }) { errorFormatter({ shape, error }) {
return { return {

View File

@@ -2,9 +2,14 @@ import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { type GetServerSidePropsContext } from "next"; import { type GetServerSidePropsContext } from "next";
import { getServerSession, type NextAuthOptions, type DefaultSession } from "next-auth"; import { getServerSession, type NextAuthOptions, type DefaultSession } from "next-auth";
import { prisma } from "~/server/db"; import { prisma } from "~/server/db";
import GitHubProvider from "next-auth/providers/github"; import GitHubModule from "next-auth/providers/github";
import { env } from "~/env.mjs"; import { env } from "~/env.mjs";
// Fix bug with GitHub module not being imported correctly during client libs codegen
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const untypedGitHubModule = GitHubModule as unknown as any;
const GitHubProvider = (untypedGitHubModule.default ? untypedGitHubModule.default : untypedGitHubModule) as typeof GitHubModule;
/** /**
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session` * Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
* object and keep type safety. * object and keep type safety.

View File

@@ -4,7 +4,7 @@ import modelProviders from "~/modelProviders/modelProviders";
import { prisma } from "~/server/db"; import { prisma } from "~/server/db";
import { wsConnection } from "~/utils/wsConnection"; import { wsConnection } from "~/utils/wsConnection";
import { runEvalsForOutput } from "../utils/evaluations"; import { runEvalsForOutput } from "../utils/evaluations";
import hashPrompt from "../utils/hashPrompt"; import hashPrompt from "../utils/hashSortedObject";
import parseConstructFn from "../utils/parseConstructFn"; import parseConstructFn from "../utils/parseConstructFn";
import defineTask from "./defineTask"; import defineTask from "./defineTask";

View File

@@ -2,7 +2,7 @@ import { Prisma } from "@prisma/client";
import { prisma } from "../db"; import { prisma } from "../db";
import parseConstructFn from "./parseConstructFn"; import parseConstructFn from "./parseConstructFn";
import { type JsonObject } from "type-fest"; import { type JsonObject } from "type-fest";
import hashPrompt from "./hashPrompt"; import hashPrompt from "./hashSortedObject";
import { omit } from "lodash-es"; import { omit } from "lodash-es";
import { queueQueryModel } from "../tasks/queryModel.task"; import { queueQueryModel } from "../tasks/queryModel.task";
@@ -100,8 +100,8 @@ export const generateNewCell = async (
where: { id: cell.id }, where: { id: cell.id },
data: { data: {
retrievalStatus: "COMPLETE", retrievalStatus: "COMPLETE",
jobStartedAt: matchingModelResponse.scenarioVariantCell.jobStartedAt, jobStartedAt: matchingModelResponse.scenarioVariantCell?.jobStartedAt,
jobQueuedAt: matchingModelResponse.scenarioVariantCell.jobQueuedAt, jobQueuedAt: matchingModelResponse.scenarioVariantCell?.jobQueuedAt,
}, },
}); });

View File

@@ -1,6 +1,5 @@
import crypto from "crypto"; import crypto from "crypto";
import { type JsonValue } from "type-fest"; import { type JsonValue } from "type-fest";
import { type ParsedConstructFn } from "./parseConstructFn";
function sortKeys(obj: JsonValue): JsonValue { function sortKeys(obj: JsonValue): JsonValue {
if (typeof obj !== "object" || obj === null) { if (typeof obj !== "object" || obj === null) {
@@ -25,12 +24,16 @@ function sortKeys(obj: JsonValue): JsonValue {
return sortedObj; return sortedObj;
} }
export default function hashPrompt(prompt: ParsedConstructFn<any>): string { export default function hashSortedObject(prompt: JsonValue): string {
// Sort object keys recursively // Sort object keys recursively
const sortedObj = sortKeys(prompt as unknown as JsonValue); const sortedObj = sortKeys(prompt as unknown as JsonValue);
// Convert to JSON and hash it // Convert to JSON and hash it
const str = JSON.stringify(sortedObj); const str = JSON.stringify(sortedObj);
return hashString(str);
}
export function hashString(str: string): string {
const hash = crypto.createHash("sha256"); const hash = crypto.createHash("sha256");
hash.update(str); hash.update(str);
return hash.digest("hex"); return hash.digest("hex");

View File

@@ -8,6 +8,27 @@ export const requireNothing = (ctx: TRPCContext) => {
ctx.markAccessControlRun(); ctx.markAccessControlRun();
}; };
export const requireCanAccessDataFlow = async (dataFlowId: string, ctx: TRPCContext) => {
if (!ctx.session?.user.id) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
const dataFlow = await prisma.dataFlow.findFirst({
where: {
id: dataFlowId,
organization: {
organizationUsers: {
some: {
role: { in: [OrganizationUserRole.ADMIN, OrganizationUserRole.MEMBER] },
userId: ctx.session?.user.id,
},
},
},
},
});
return !!dataFlow;
};
export const requireCanViewExperiment = async (experimentId: string, ctx: TRPCContext) => { export const requireCanViewExperiment = async (experimentId: string, ctx: TRPCContext) => {
await prisma.experiment.findFirst({ await prisma.experiment.findFirst({
where: { id: experimentId }, where: { id: experimentId },

3
client-libs/js/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
wwwroot/*.js
node_modules
dist

4
client-libs/js/codegen/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
wwwroot/*.js
node_modules
typings
dist

View File

@@ -0,0 +1 @@
# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm

View File

@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@@ -0,0 +1,9 @@
.gitignore
.npmignore
.openapi-generator-ignore
api.ts
base.ts
common.ts
configuration.ts
git_push.sh
index.ts

View File

@@ -0,0 +1 @@
6.6.0

View File

@@ -0,0 +1,306 @@
/* tslint:disable */
/* eslint-disable */
/**
* OpenPipe API
* The public API for reporting API calls to OpenPipe
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import type { Configuration } from './configuration';
import type { AxiosPromise, AxiosInstance, AxiosRequestConfig } from 'axios';
import globalAxios from 'axios';
// Some imports not used depending on template conditions
// @ts-ignore
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from './common';
import type { RequestArgs } from './base';
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError } from './base';
/**
*
* @export
* @interface ExternalApiCapturePromptDefaultResponse
*/
export interface ExternalApiCapturePromptDefaultResponse {
/**
*
* @type {string}
* @memberof ExternalApiCapturePromptDefaultResponse
*/
'message': string;
/**
*
* @type {string}
* @memberof ExternalApiCapturePromptDefaultResponse
*/
'code': string;
/**
*
* @type {Array<ExternalApiCapturePromptDefaultResponseIssuesInner>}
* @memberof ExternalApiCapturePromptDefaultResponse
*/
'issues'?: Array<ExternalApiCapturePromptDefaultResponseIssuesInner>;
}
/**
*
* @export
* @interface ExternalApiCapturePromptDefaultResponseIssuesInner
*/
export interface ExternalApiCapturePromptDefaultResponseIssuesInner {
/**
*
* @type {string}
* @memberof ExternalApiCapturePromptDefaultResponseIssuesInner
*/
'message': string;
}
/**
*
* @export
* @interface ExternalApiCapturePromptRequest
*/
export interface ExternalApiCapturePromptRequest {
/**
* API token for authentication
* @type {string}
* @memberof ExternalApiCapturePromptRequest
*/
'apiKey': string;
/**
* Data flow ID
* @type {string}
* @memberof ExternalApiCapturePromptRequest
*/
'dataFlowId': string;
/**
* Prompt construction function
* @type {string}
* @memberof ExternalApiCapturePromptRequest
*/
'promptFunction': string;
/**
* Scenario variables as JSON
* @type {any}
* @memberof ExternalApiCapturePromptRequest
*/
'scenarioVariables'?: any;
/**
* Prompt object as JSON
* @type {any}
* @memberof ExternalApiCapturePromptRequest
*/
'prompt'?: any;
/**
* Model name
* @type {string}
* @memberof ExternalApiCapturePromptRequest
*/
'model': string;
/**
* Model provider
* @type {string}
* @memberof ExternalApiCapturePromptRequest
*/
'modelProvider': string;
}
/**
*
* @export
* @interface ExternalApiCaptureResponseRequest
*/
export interface ExternalApiCaptureResponseRequest {
/**
* API token for authentication
* @type {string}
* @memberof ExternalApiCaptureResponseRequest
*/
'apiKey': string;
/**
* Logged call ID
* @type {string}
* @memberof ExternalApiCaptureResponseRequest
*/
'loggedCallId': string;
/**
* JSON-encoded response payload
* @type {any}
* @memberof ExternalApiCaptureResponseRequest
*/
'responsePayload'?: any;
}
/**
* DefaultApi - axios parameter creator
* @export
*/
export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) {
return {
/**
* Capture a prompt with its variables call
* @param {ExternalApiCapturePromptRequest} externalApiCapturePromptRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
externalApiCapturePrompt: async (externalApiCapturePromptRequest: ExternalApiCapturePromptRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'externalApiCapturePromptRequest' is not null or undefined
assertParamExists('externalApiCapturePrompt', 'externalApiCapturePromptRequest', externalApiCapturePromptRequest)
const localVarPath = `/v1/capture-prompt`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
localVarHeaderParameter['Content-Type'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(externalApiCapturePromptRequest, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Capture a response to a prompt
* @param {ExternalApiCaptureResponseRequest} externalApiCaptureResponseRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
externalApiCaptureResponse: async (externalApiCaptureResponseRequest: ExternalApiCaptureResponseRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'externalApiCaptureResponseRequest' is not null or undefined
assertParamExists('externalApiCaptureResponse', 'externalApiCaptureResponseRequest', externalApiCaptureResponseRequest)
const localVarPath = `/v1/capture-response`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
localVarHeaderParameter['Content-Type'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(externalApiCaptureResponseRequest, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
}
};
/**
* DefaultApi - functional programming interface
* @export
*/
export const DefaultApiFp = function(configuration?: Configuration) {
const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration)
return {
/**
* Capture a prompt with its variables call
* @param {ExternalApiCapturePromptRequest} externalApiCapturePromptRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async externalApiCapturePrompt(externalApiCapturePromptRequest: ExternalApiCapturePromptRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<string>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.externalApiCapturePrompt(externalApiCapturePromptRequest, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
* Capture a response to a prompt
* @param {ExternalApiCaptureResponseRequest} externalApiCaptureResponseRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async externalApiCaptureResponse(externalApiCaptureResponseRequest: ExternalApiCaptureResponseRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<any>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.externalApiCaptureResponse(externalApiCaptureResponseRequest, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
}
};
/**
* DefaultApi - factory interface
* @export
*/
export const DefaultApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
const localVarFp = DefaultApiFp(configuration)
return {
/**
* Capture a prompt with its variables call
* @param {ExternalApiCapturePromptRequest} externalApiCapturePromptRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
externalApiCapturePrompt(externalApiCapturePromptRequest: ExternalApiCapturePromptRequest, options?: any): AxiosPromise<string> {
return localVarFp.externalApiCapturePrompt(externalApiCapturePromptRequest, options).then((request) => request(axios, basePath));
},
/**
* Capture a response to a prompt
* @param {ExternalApiCaptureResponseRequest} externalApiCaptureResponseRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
externalApiCaptureResponse(externalApiCaptureResponseRequest: ExternalApiCaptureResponseRequest, options?: any): AxiosPromise<any> {
return localVarFp.externalApiCaptureResponse(externalApiCaptureResponseRequest, options).then((request) => request(axios, basePath));
},
};
};
/**
* DefaultApi - object-oriented interface
* @export
* @class DefaultApi
* @extends {BaseAPI}
*/
export class DefaultApi extends BaseAPI {
/**
* Capture a prompt with its variables call
* @param {ExternalApiCapturePromptRequest} externalApiCapturePromptRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof DefaultApi
*/
public externalApiCapturePrompt(externalApiCapturePromptRequest: ExternalApiCapturePromptRequest, options?: AxiosRequestConfig) {
return DefaultApiFp(this.configuration).externalApiCapturePrompt(externalApiCapturePromptRequest, options).then((request) => request(this.axios, this.basePath));
}
/**
* Capture a response to a prompt
* @param {ExternalApiCaptureResponseRequest} externalApiCaptureResponseRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof DefaultApi
*/
public externalApiCaptureResponse(externalApiCaptureResponseRequest: ExternalApiCaptureResponseRequest, options?: AxiosRequestConfig) {
return DefaultApiFp(this.configuration).externalApiCaptureResponse(externalApiCaptureResponseRequest, options).then((request) => request(this.axios, this.basePath));
}
}

View File

@@ -0,0 +1,72 @@
/* tslint:disable */
/* eslint-disable */
/**
* OpenPipe API
* The public API for reporting API calls to OpenPipe
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import type { Configuration } from './configuration';
// Some imports not used depending on template conditions
// @ts-ignore
import type { AxiosPromise, AxiosInstance, AxiosRequestConfig } from 'axios';
import globalAxios from 'axios';
export const BASE_PATH = "https://app.openpipe.ai/api".replace(/\/+$/, "");
/**
*
* @export
*/
export const COLLECTION_FORMATS = {
csv: ",",
ssv: " ",
tsv: "\t",
pipes: "|",
};
/**
*
* @export
* @interface RequestArgs
*/
export interface RequestArgs {
url: string;
options: AxiosRequestConfig;
}
/**
*
* @export
* @class BaseAPI
*/
export class BaseAPI {
protected configuration: Configuration | undefined;
constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) {
if (configuration) {
this.configuration = configuration;
this.basePath = configuration.basePath || this.basePath;
}
}
};
/**
*
* @export
* @class RequiredError
* @extends {Error}
*/
export class RequiredError extends Error {
constructor(public field: string, msg?: string) {
super(msg);
this.name = "RequiredError"
}
}

View File

@@ -0,0 +1,150 @@
/* tslint:disable */
/* eslint-disable */
/**
* OpenPipe API
* The public API for reporting API calls to OpenPipe
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import type { Configuration } from "./configuration";
import type { RequestArgs } from "./base";
import type { AxiosInstance, AxiosResponse } from 'axios';
import { RequiredError } from "./base";
/**
*
* @export
*/
export const DUMMY_BASE_URL = 'https://example.com'
/**
*
* @throws {RequiredError}
* @export
*/
export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) {
if (paramValue === null || paramValue === undefined) {
throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`);
}
}
/**
*
* @export
*/
export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) {
if (configuration && configuration.apiKey) {
const localVarApiKeyValue = typeof configuration.apiKey === 'function'
? await configuration.apiKey(keyParamName)
: await configuration.apiKey;
object[keyParamName] = localVarApiKeyValue;
}
}
/**
*
* @export
*/
export const setBasicAuthToObject = function (object: any, configuration?: Configuration) {
if (configuration && (configuration.username || configuration.password)) {
object["auth"] = { username: configuration.username, password: configuration.password };
}
}
/**
*
* @export
*/
export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) {
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
object["Authorization"] = "Bearer " + accessToken;
}
}
/**
*
* @export
*/
export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) {
if (configuration && configuration.accessToken) {
const localVarAccessTokenValue = typeof configuration.accessToken === 'function'
? await configuration.accessToken(name, scopes)
: await configuration.accessToken;
object["Authorization"] = "Bearer " + localVarAccessTokenValue;
}
}
function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void {
if (parameter == null) return;
if (typeof parameter === "object") {
if (Array.isArray(parameter)) {
(parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key));
}
else {
Object.keys(parameter).forEach(currentKey =>
setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== '' ? '.' : ''}${currentKey}`)
);
}
}
else {
if (urlSearchParams.has(key)) {
urlSearchParams.append(key, parameter);
}
else {
urlSearchParams.set(key, parameter);
}
}
}
/**
*
* @export
*/
export const setSearchParams = function (url: URL, ...objects: any[]) {
const searchParams = new URLSearchParams(url.search);
setFlattenedQueryParams(searchParams, objects);
url.search = searchParams.toString();
}
/**
*
* @export
*/
export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) {
const nonString = typeof value !== 'string';
const needsSerialization = nonString && configuration && configuration.isJsonMime
? configuration.isJsonMime(requestOptions.headers['Content-Type'])
: nonString;
return needsSerialization
? JSON.stringify(value !== undefined ? value : {})
: (value || "");
}
/**
*
* @export
*/
export const toPathString = function (url: URL) {
return url.pathname + url.search + url.hash
}
/**
*
* @export
*/
export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) {
return <T = unknown, R = AxiosResponse<T>>(axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs = {...axiosArgs.options, url: (configuration?.basePath || basePath) + axiosArgs.url};
return axios.request<T, R>(axiosRequestArgs);
};
}

View File

@@ -0,0 +1,101 @@
/* tslint:disable */
/* eslint-disable */
/**
* OpenPipe API
* The public API for reporting API calls to OpenPipe
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export interface ConfigurationParameters {
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
username?: string;
password?: string;
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
basePath?: string;
baseOptions?: any;
formDataCtor?: new () => any;
}
export class Configuration {
/**
* parameter for apiKey security
* @param name security name
* @memberof Configuration
*/
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
/**
* parameter for basic security
*
* @type {string}
* @memberof Configuration
*/
username?: string;
/**
* parameter for basic security
*
* @type {string}
* @memberof Configuration
*/
password?: string;
/**
* parameter for oauth2 security
* @param name security name
* @param scopes oauth2 scope
* @memberof Configuration
*/
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
/**
* override base path
*
* @type {string}
* @memberof Configuration
*/
basePath?: string;
/**
* base options for axios calls
*
* @type {any}
* @memberof Configuration
*/
baseOptions?: any;
/**
* The FormData constructor that will be used to create multipart form data
* requests. You can inject this here so that execution environments that
* do not support the FormData class can still run the generated client.
*
* @type {new () => FormData}
*/
formDataCtor?: new () => any;
constructor(param: ConfigurationParameters = {}) {
this.apiKey = param.apiKey;
this.username = param.username;
this.password = param.password;
this.accessToken = param.accessToken;
this.basePath = param.basePath;
this.baseOptions = param.baseOptions;
this.formDataCtor = param.formDataCtor;
}
/**
* Check if the given MIME is a JSON MIME.
* JSON MIME examples:
* application/json
* application/json; charset=UTF8
* APPLICATION/JSON
* application/vnd.company+json
* @param mime - MIME (Multipurpose Internet Mail Extensions)
* @return True if the given MIME is JSON, false otherwise.
*/
public isJsonMime(mime: string): boolean {
const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i');
return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
}
}

View File

@@ -0,0 +1,57 @@
#!/bin/sh
# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
#
# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com"
git_user_id=$1
git_repo_id=$2
release_note=$3
git_host=$4
if [ "$git_host" = "" ]; then
git_host="github.com"
echo "[INFO] No command line input provided. Set \$git_host to $git_host"
fi
if [ "$git_user_id" = "" ]; then
git_user_id="GIT_USER_ID"
echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id"
fi
if [ "$git_repo_id" = "" ]; then
git_repo_id="GIT_REPO_ID"
echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id"
fi
if [ "$release_note" = "" ]; then
release_note="Minor update"
echo "[INFO] No command line input provided. Set \$release_note to $release_note"
fi
# Initialize the local directory as a Git repository
git init
# Adds the files in the local repository and stages them for commit.
git add .
# Commits the tracked changes and prepares them to be pushed to a remote repository.
git commit -m "$release_note"
# Sets the new remote
git_remote=$(git remote)
if [ "$git_remote" = "" ]; then # git remote not defined
if [ "$GIT_TOKEN" = "" ]; then
echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment."
git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git
else
git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git
fi
fi
git pull origin master
# Pushes (Forces) the changes in the local repository up to the remote repository
echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git"
git push origin master 2>&1 | grep -v 'To https'

View File

@@ -0,0 +1,18 @@
/* tslint:disable */
/* eslint-disable */
/**
* OpenPipe API
* The public API for reporting API calls to OpenPipe
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export * from "./api";
export * from "./configuration";

View File

@@ -0,0 +1,300 @@
/**
* This type map defines the input types for each model provider.
*/
export interface PromptTypes {
"openai/ChatCompletion"?: {
/**
* ID of the model to use. See the [model endpoint compatibility](/docs/models/model-endpoint-compatibility) table for details on which models work with the Chat API.
*/
model:
| "gpt-4"
| "gpt-4-0613"
| "gpt-4-32k"
| "gpt-4-32k-0613"
| "gpt-3.5-turbo"
| "gpt-3.5-turbo-16k"
| "gpt-3.5-turbo-0613"
| "gpt-3.5-turbo-16k-0613";
/**
* A list of messages comprising the conversation so far. [Example Python code](https://github.com/openai/openai-cookbook/blob/main/examples/How_to_format_inputs_to_ChatGPT_models.ipynb).
*
* @minItems 1
*/
messages: [
{
/**
* The role of the messages author. One of `system`, `user`, `assistant`, or `function`.
*/
role: "system" | "user" | "assistant" | "function";
/**
* The contents of the message. `content` is required for all messages except assistant messages with function calls.
*/
content?: string;
/**
* The name of the author of this message. `name` is required if role is `function`, and it should be the name of the function whose response is in the `content`. May contain a-z, A-Z, 0-9, and underscores, with a maximum length of 64 characters.
*/
name?: string;
/**
* The name and arguments of a function that should be called, as generated by the model.
*/
function_call?: {
/**
* The name of the function to call.
*/
name?: string;
/**
* The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function.
*/
arguments?: string;
};
},
...{
/**
* The role of the messages author. One of `system`, `user`, `assistant`, or `function`.
*/
role: "system" | "user" | "assistant" | "function";
/**
* The contents of the message. `content` is required for all messages except assistant messages with function calls.
*/
content?: string;
/**
* The name of the author of this message. `name` is required if role is `function`, and it should be the name of the function whose response is in the `content`. May contain a-z, A-Z, 0-9, and underscores, with a maximum length of 64 characters.
*/
name?: string;
/**
* The name and arguments of a function that should be called, as generated by the model.
*/
function_call?: {
/**
* The name of the function to call.
*/
name?: string;
/**
* The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function.
*/
arguments?: string;
};
}[]
];
/**
* A list of functions the model may generate JSON inputs for.
*
* @minItems 1
*/
functions?: [
{
/**
* The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.
*/
name: string;
/**
* The description of what the function does.
*/
description?: string;
/**
* The parameters the functions accepts, described as a JSON Schema object. See the [guide](/docs/guides/gpt/function-calling) for examples, and the [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for documentation about the format.
*/
parameters?: {
[k: string]: unknown;
};
},
...{
/**
* The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.
*/
name: string;
/**
* The description of what the function does.
*/
description?: string;
/**
* The parameters the functions accepts, described as a JSON Schema object. See the [guide](/docs/guides/gpt/function-calling) for examples, and the [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for documentation about the format.
*/
parameters?: {
[k: string]: unknown;
};
}[]
];
/**
* Controls how the model responds to function calls. "none" means the model does not call a function, and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. Specifying a particular function via `{"name":\ "my_function"}` forces the model to call that function. "none" is the default when no functions are present. "auto" is the default if functions are present.
*/
function_call?:
| ("none" | "auto")
| {
/**
* The name of the function to call.
*/
name: string;
};
/**
* What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.
*
* We generally recommend altering this or `top_p` but not both.
*
*/
temperature?: number;
/**
* An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.
*
* We generally recommend altering this or `temperature` but not both.
*
*/
top_p?: number;
/**
* How many chat completion choices to generate for each input message.
*/
n?: number;
/**
* If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) as they become available, with the stream terminated by a `data: [DONE]` message. [Example Python code](https://github.com/openai/openai-cookbook/blob/main/examples/How_to_stream_completions.ipynb).
*
*/
stream?: boolean;
/**
* Up to 4 sequences where the API will stop generating further tokens.
*
*/
stop?: string | [string] | [string, string] | [string, string, string] | [string, string, string, string];
/**
* The maximum number of [tokens](/tokenizer) to generate in the chat completion.
*
* The total length of input tokens and generated tokens is limited by the model's context length. [Example Python code](https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb) for counting tokens.
*
*/
max_tokens?: number;
/**
* Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.
*
* [See more information about frequency and presence penalties.](/docs/api-reference/parameter-details)
*
*/
presence_penalty?: number;
/**
* Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.
*
* [See more information about frequency and presence penalties.](/docs/api-reference/parameter-details)
*
*/
frequency_penalty?: number;
/**
* Modify the likelihood of specified tokens appearing in the completion.
*
* Accepts a json object that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from -100 to 100. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token.
*
*/
logit_bias?: {};
/**
* A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. [Learn more](/docs/guides/safety-best-practices/end-user-ids).
*
*/
user?: string;
};
"replicate/llama2"?: {
model: "7b-chat" | "13b-chat" | "70b-chat";
/**
* System prompt to send to Llama v2. This is prepended to the prompt and helps guide system behavior.
*/
system_prompt?: string;
/**
* Prompt to send to Llama v2.
*/
prompt: string;
/**
* Maximum number of tokens to generate. A word is generally 2-3 tokens (minimum: 1)
*/
max_new_tokens?: number;
/**
* Adjusts randomness of outputs, greater than 1 is random and 0 is deterministic, 0.75 is a good starting value. (minimum: 0.01; maximum: 5)
*/
temperature?: number;
/**
* When decoding text, samples from the top p percentage of most likely tokens; lower to ignore less likely tokens (minimum: 0.01; maximum: 1)
*/
top_p?: number;
/**
* Penalty for repeated words in generated text; 1 is no penalty, values greater than 1 discourage repetition, less than 1 encourage it. (minimum: 0.01; maximum: 5)
*/
repetition_penalty?: number;
/**
* provide debugging output in logs
*/
debug?: boolean;
};
anthropic?: {
/**
* The model that will complete your prompt.
* As we improve Claude, we develop new versions of it that you can query.
* This parameter controls which version of Claude answers your request.
* Right now we are offering two model families: Claude, and Claude Instant.
* You can use them by setting model to "claude-2" or "claude-instant-1", respectively.
* See models for additional details.
*
*/
model: "claude-2" | "claude-2.0" | "claude-instant-1" | "claude-instant-1.1";
/**
* The prompt that you want Claude to complete.
*
* For proper response generation you will need to format your prompt as follows:
* \n\nHuman: ${userQuestion}\n\nAssistant:
* See our comments on prompts for more context.
*
*/
prompt: string | string[] | [number, ...number[]] | [[number, ...number[]], ...[number, ...number[]][]];
/**
* The maximum number of tokens to generate before stopping.
*
* Note that our models may stop before reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate.
*
*/
max_tokens_to_sample: number;
/**
* Amount of randomness injected into the response.
*
* Defaults to 1. Ranges from 0 to 1. Use temp closer to 0 for analytical / multiple choice, and closer to 1 for creative and generative tasks.
*
*/
temperature?: number;
/**
* Use nucleus sampling.
*
* In nucleus sampling, we compute the cumulative distribution over all the options
* for each subsequent token in decreasing probability order and cut it off once
* it reaches a particular probability specified by top_p. You should either alter temperature or top_p, but not both.
*
*/
top_p?: number;
/**
* Only sample from the top K options for each subsequent token.
*
* Used to remove "long tail" low probability responses. Learn more technical details here.
*
*/
top_k?: number;
/**
* Whether to incrementally stream the response using server-sent events.
* See this guide to SSE events for details.type: boolean
*
*/
stream?: boolean;
/**
* Sequences that will cause the model to stop generating completion text.
* Our models stop on "\n\nHuman:", and may include additional built-in stop sequences in the future. By providing the stop_sequences parameter, you may include additional strings that will cause the model to stop generating.
*
*/
stop_sequences?: string | [string] | [string, string] | [string, string, string] | [string, string, string, string];
/**
* An object describing metadata about the request.
*
*/
metadata?: {
/**
* An external identifier for the user who is associated with the request.
*
* This should be a uuid, hash value, or other opaque identifier. Anthropic may use this id to help detect abuse.
* Do not include any identifying information such as name, email address, or phone number.
*
*/
user_id?: string;
};
};
}

89
client-libs/js/index.ts Normal file
View File

@@ -0,0 +1,89 @@
import * as opClient from "./codegen";
import { PromptTypes } from "./codegen/promptTypes";
import { version } from "./package.json";
type OPConfigOptions = {
apiKey?: string;
basePath?: string;
};
export class Configuration {
public opConfig?: opClient.Configuration;
// TODO: use OpenAPI apiKey or something similar
public apiKey: string;
constructor(config: { opOptions?: OPConfigOptions }) {
if (config.opOptions) {
this.opConfig = new opClient.Configuration(config.opOptions);
this.apiKey = config.opOptions.apiKey ?? "";
}
}
}
export class OpenPipeApi {
public opApi?: opClient.DefaultApi;
private apiKey: string;
constructor(config: Configuration) {
if (config.opConfig) {
this.opApi = new opClient.DefaultApi(config.opConfig);
this.apiKey = config.apiKey;
}
}
public async capturePrompt<T extends keyof PromptTypes>(
dataFlowId: string,
modelProvider: T,
promptFunction: () => PromptTypes[T],
scenarioVariables: Record<string, unknown>
): Promise<{
id?: string;
prompt: PromptTypes[T];
}> {
const prompt = promptFunction() as PromptTypes[T];
if (!prompt) {
console.error("Prompt function returned null", promptFunction.toString());
}
const promptFunctionString = promptFunction.toString();
const startTime = Date.now();
let resp;
try {
resp = await this.opApi?.externalApiCapturePrompt({
apiKey: this.apiKey,
dataFlowId,
promptFunction: promptFunctionString,
scenarioVariables,
model: "",
modelProvider,
prompt,
});
} catch (err) {
console.error("Error reporting to OpenPipe", err);
}
return {
id: resp?.data?.loggedCallId,
prompt,
}
}
public async captureResponse(loggedCallId: string | undefined, responsePayload: any): Promise<void> {
if (!loggedCallId) {
console.error("No call log ID provided to captureResponse");
return;
}
try {
await this.opApi?.externalApiCaptureResponse({
apiKey: this.apiKey,
loggedCallId,
responsePayload,
});
} catch (err) {
console.error("Error reporting to OpenPipe", err);
}
}
}

View File

@@ -0,0 +1,21 @@
{
"name": "openai-js",
"version": "0.1.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.4.0",
"openai": "^3.3.0"
},
"devDependencies": {
"dotenv": "^16.3.1",
"tsx": "^3.12.7",
"typescript": "^5.1.6"
}
}

409
client-libs/js/pnpm-lock.yaml generated Normal file
View File

@@ -0,0 +1,409 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
axios:
specifier: ^1.4.0
version: 1.4.0
openai:
specifier: ^3.3.0
version: 3.3.0
devDependencies:
dotenv:
specifier: ^16.3.1
version: 16.3.1
tsx:
specifier: ^3.12.7
version: 3.12.7
typescript:
specifier: ^5.1.6
version: 5.1.6
packages:
/@esbuild-kit/cjs-loader@2.4.2:
resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==}
dependencies:
'@esbuild-kit/core-utils': 3.1.0
get-tsconfig: 4.6.2
dev: true
/@esbuild-kit/core-utils@3.1.0:
resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==}
dependencies:
esbuild: 0.17.19
source-map-support: 0.5.21
dev: true
/@esbuild-kit/esm-loader@2.5.5:
resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==}
dependencies:
'@esbuild-kit/core-utils': 3.1.0
get-tsconfig: 4.6.2
dev: true
/@esbuild/android-arm64@0.17.19:
resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-arm@0.17.19:
resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-x64@0.17.19:
resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-arm64@0.17.19:
resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-x64@0.17.19:
resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-arm64@0.17.19:
resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-x64@0.17.19:
resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm64@0.17.19:
resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm@0.17.19:
resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ia32@0.17.19:
resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-loong64@0.17.19:
resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-mips64el@0.17.19:
resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ppc64@0.17.19:
resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-riscv64@0.17.19:
resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-s390x@0.17.19:
resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-x64@0.17.19:
resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/netbsd-x64@0.17.19:
resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/openbsd-x64@0.17.19:
resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/sunos-x64@0.17.19:
resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-arm64@0.17.19:
resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-ia32@0.17.19:
resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-x64@0.17.19:
resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
/axios@0.26.1:
resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==}
dependencies:
follow-redirects: 1.15.2
transitivePeerDependencies:
- debug
dev: false
/axios@1.4.0:
resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==}
dependencies:
follow-redirects: 1.15.2
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
dev: false
/buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
/combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: false
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dev: false
/dotenv@16.3.1:
resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==}
engines: {node: '>=12'}
dev: true
/esbuild@0.17.19:
resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/android-arm': 0.17.19
'@esbuild/android-arm64': 0.17.19
'@esbuild/android-x64': 0.17.19
'@esbuild/darwin-arm64': 0.17.19
'@esbuild/darwin-x64': 0.17.19
'@esbuild/freebsd-arm64': 0.17.19
'@esbuild/freebsd-x64': 0.17.19
'@esbuild/linux-arm': 0.17.19
'@esbuild/linux-arm64': 0.17.19
'@esbuild/linux-ia32': 0.17.19
'@esbuild/linux-loong64': 0.17.19
'@esbuild/linux-mips64el': 0.17.19
'@esbuild/linux-ppc64': 0.17.19
'@esbuild/linux-riscv64': 0.17.19
'@esbuild/linux-s390x': 0.17.19
'@esbuild/linux-x64': 0.17.19
'@esbuild/netbsd-x64': 0.17.19
'@esbuild/openbsd-x64': 0.17.19
'@esbuild/sunos-x64': 0.17.19
'@esbuild/win32-arm64': 0.17.19
'@esbuild/win32-ia32': 0.17.19
'@esbuild/win32-x64': 0.17.19
dev: true
/follow-redirects@1.15.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
dev: false
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: false
/fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
dev: true
optional: true
/get-tsconfig@4.6.2:
resolution: {integrity: sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg==}
dependencies:
resolve-pkg-maps: 1.0.0
dev: true
/mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
dev: false
/mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
dev: false
/openai@3.3.0:
resolution: {integrity: sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ==}
dependencies:
axios: 0.26.1
form-data: 4.0.0
transitivePeerDependencies:
- debug
dev: false
/proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
dev: false
/resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
dev: true
/source-map-support@0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
dependencies:
buffer-from: 1.1.2
source-map: 0.6.1
dev: true
/source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
dev: true
/tsx@3.12.7:
resolution: {integrity: sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==}
hasBin: true
dependencies:
'@esbuild-kit/cjs-loader': 2.4.2
'@esbuild-kit/core-utils': 3.1.0
'@esbuild-kit/esm-loader': 2.5.5
optionalDependencies:
fsevents: 2.3.2
dev: true
/typescript@5.1.6:
resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==}
engines: {node: '>=14.17'}
hasBin: true
dev: true

View File

@@ -0,0 +1,45 @@
import "dotenv/config";
import { Configuration, OpenPipeApi } from "../index";
const config = new Configuration({
opOptions: {
apiKey: "mock-key",
basePath: "http://localhost:3000/api",
},
});
const client = new OpenPipeApi(config);
async function main() {
const prompt = client.capturePrompt(
"123",
"openai/ChatCompletion",
() => ({
model: "gpt-3.5-turbo",
messages: [
{
role: "system",
content: "count to 3 in french",
},
],
}),
{}
);
const response = await client.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [
{
role: "system",
content: "count to 3 in french",
},
],
});
console.log("got response", response.data);
}
main().catch((err) => {
console.log("exited with error");
// console.error(err);
});

179
client-libs/schema.json Normal file
View File

@@ -0,0 +1,179 @@
{
"openapi": "3.0.3",
"info": {
"title": "OpenPipe API",
"description": "The public API for reporting API calls to OpenPipe",
"version": "0.1.0"
},
"servers": [
{
"url": "https://app.openpipe.ai/api"
}
],
"paths": {
"/v1/capture-prompt": {
"post": {
"operationId": "externalApi-capturePrompt",
"description": "Capture a prompt with its variables call",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"apiKey": {
"type": "string",
"description": "API token for authentication"
},
"dataFlowId": {
"type": "string",
"description": "Data flow ID"
},
"promptFunction": {
"type": "string",
"description": "Prompt construction function"
},
"scenarioVariables": {
"description": "Scenario variables as JSON"
},
"prompt": {
"description": "Prompt object as JSON"
},
"model": {
"type": "string",
"description": "Model name"
},
"modelProvider": {
"type": "string",
"description": "Model provider"
}
},
"required": [
"apiKey",
"dataFlowId",
"promptFunction",
"model",
"modelProvider"
],
"additionalProperties": false
}
}
}
},
"parameters": [],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
}
},
"/v1/capture-response": {
"post": {
"operationId": "externalApi-captureResponse",
"description": "Capture a response to a prompt",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"apiKey": {
"type": "string",
"description": "API token for authentication"
},
"loggedCallId": {
"type": "string",
"description": "Logged call ID"
},
"responsePayload": {
"description": "JSON-encoded response payload"
}
},
"required": [
"apiKey",
"loggedCallId"
],
"additionalProperties": false
}
}
}
},
"parameters": [],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
}
}
},
"components": {
"securitySchemes": {
"Authorization": {
"type": "http",
"scheme": "bearer"
}
},
"responses": {
"error": {
"description": "Error response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"code": {
"type": "string"
},
"issues": {
"type": "array",
"items": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
],
"additionalProperties": false
}
}
},
"required": [
"message",
"code"
],
"additionalProperties": false
}
}
}
}
}
}
}