TypeScript SDK mostly working
Ok so this is still pretty rough, and notably there's no reporting for streaming. But for non-streaming requests I've verified that this does in fact report requests locally.
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
// main.ts or index.ts at the root level
|
||||
export * as OpenAI from './openai';
|
||||
export * as OpenAILegacy from './openai-legacy';
|
||||
export * as OpenAI from "./src/openai";
|
||||
export * as OpenAILegacy from "./src/openai-legacy";
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"type": "module",
|
||||
"description": "Metrics and auto-evaluation for LLM calls",
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
"build": "tsc",
|
||||
"test": "vitest"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@@ -12,7 +13,8 @@
|
||||
"author": "",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"axios": "^0.26.0",
|
||||
"form-data": "^4.0.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"openai-beta": "npm:openai@4.0.0-beta.7",
|
||||
"openai-legacy": "npm:openai@3.3.0"
|
||||
},
|
||||
@@ -20,6 +22,7 @@
|
||||
"@types/node": "^20.4.8",
|
||||
"dotenv": "^16.3.1",
|
||||
"tsx": "^3.12.7",
|
||||
"typescript": "^5.0.4"
|
||||
"typescript": "^5.0.4",
|
||||
"vitest": "^0.33.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
wwwroot/*.js
|
||||
node_modules
|
||||
typings
|
||||
dist
|
||||
@@ -1 +0,0 @@
|
||||
# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm
|
||||
@@ -1,23 +0,0 @@
|
||||
# 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
|
||||
@@ -1,9 +0,0 @@
|
||||
.gitignore
|
||||
.npmignore
|
||||
.openapi-generator-ignore
|
||||
api.ts
|
||||
base.ts
|
||||
common.ts
|
||||
configuration.ts
|
||||
git_push.sh
|
||||
index.ts
|
||||
@@ -1 +0,0 @@
|
||||
6.6.0
|
||||
35
client-libs/typescript/src/codegen/OPClient.ts
Normal file
35
client-libs/typescript/src/codegen/OPClient.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { BaseHttpRequest } from './core/BaseHttpRequest';
|
||||
import type { OpenAPIConfig } from './core/OpenAPI';
|
||||
import { NodeHttpRequest } from './core/NodeHttpRequest';
|
||||
|
||||
import { DefaultService } from './services/DefaultService';
|
||||
|
||||
type HttpRequestConstructor = new (config: OpenAPIConfig) => BaseHttpRequest;
|
||||
|
||||
export class OPClient {
|
||||
|
||||
public readonly default: DefaultService;
|
||||
|
||||
public readonly request: BaseHttpRequest;
|
||||
|
||||
constructor(config?: Partial<OpenAPIConfig>, HttpRequest: HttpRequestConstructor = NodeHttpRequest) {
|
||||
this.request = new HttpRequest({
|
||||
BASE: config?.BASE ?? 'https://app.openpipe.ai/api/v1',
|
||||
VERSION: config?.VERSION ?? '0.1.1',
|
||||
WITH_CREDENTIALS: config?.WITH_CREDENTIALS ?? false,
|
||||
CREDENTIALS: config?.CREDENTIALS ?? 'include',
|
||||
TOKEN: config?.TOKEN,
|
||||
USERNAME: config?.USERNAME,
|
||||
PASSWORD: config?.PASSWORD,
|
||||
HEADERS: config?.HEADERS,
|
||||
ENCODE_PATH: config?.ENCODE_PATH,
|
||||
});
|
||||
|
||||
this.default = new DefaultService(this.request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,455 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* OpenPipe API
|
||||
* The public API for reporting API calls to OpenPipe
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.1
|
||||
*
|
||||
*
|
||||
* 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 CheckCache200Response
|
||||
*/
|
||||
export interface CheckCache200Response {
|
||||
/**
|
||||
* JSON-encoded response payload
|
||||
* @type {any}
|
||||
* @memberof CheckCache200Response
|
||||
*/
|
||||
'respPayload'?: any;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface CheckCacheDefaultResponse
|
||||
*/
|
||||
export interface CheckCacheDefaultResponse {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof CheckCacheDefaultResponse
|
||||
*/
|
||||
'message': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof CheckCacheDefaultResponse
|
||||
*/
|
||||
'code': string;
|
||||
/**
|
||||
*
|
||||
* @type {Array<CheckCacheDefaultResponseIssuesInner>}
|
||||
* @memberof CheckCacheDefaultResponse
|
||||
*/
|
||||
'issues'?: Array<CheckCacheDefaultResponseIssuesInner>;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface CheckCacheDefaultResponseIssuesInner
|
||||
*/
|
||||
export interface CheckCacheDefaultResponseIssuesInner {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof CheckCacheDefaultResponseIssuesInner
|
||||
*/
|
||||
'message': string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface CheckCacheRequest
|
||||
*/
|
||||
export interface CheckCacheRequest {
|
||||
/**
|
||||
* Unix timestamp in milliseconds
|
||||
* @type {number}
|
||||
* @memberof CheckCacheRequest
|
||||
*/
|
||||
'requestedAt': number;
|
||||
/**
|
||||
* JSON-encoded request payload
|
||||
* @type {any}
|
||||
* @memberof CheckCacheRequest
|
||||
*/
|
||||
'reqPayload'?: any;
|
||||
/**
|
||||
* Extra tags to attach to the call for filtering. Eg { \"userId\": \"123\", \"promptId\": \"populate-title\" }
|
||||
* @type {{ [key: string]: string; }}
|
||||
* @memberof CheckCacheRequest
|
||||
*/
|
||||
'tags'?: { [key: string]: string; };
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface LocalTestingOnlyGetLatestLoggedCall200Response
|
||||
*/
|
||||
export interface LocalTestingOnlyGetLatestLoggedCall200Response {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof LocalTestingOnlyGetLatestLoggedCall200Response
|
||||
*/
|
||||
'createdAt': string;
|
||||
/**
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof LocalTestingOnlyGetLatestLoggedCall200Response
|
||||
*/
|
||||
'cacheHit': boolean;
|
||||
/**
|
||||
*
|
||||
* @type {{ [key: string]: string; }}
|
||||
* @memberof LocalTestingOnlyGetLatestLoggedCall200Response
|
||||
*/
|
||||
'tags': { [key: string]: string; };
|
||||
/**
|
||||
*
|
||||
* @type {LocalTestingOnlyGetLatestLoggedCall200ResponseModelResponse}
|
||||
* @memberof LocalTestingOnlyGetLatestLoggedCall200Response
|
||||
*/
|
||||
'modelResponse': LocalTestingOnlyGetLatestLoggedCall200ResponseModelResponse | null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface LocalTestingOnlyGetLatestLoggedCall200ResponseModelResponse
|
||||
*/
|
||||
export interface LocalTestingOnlyGetLatestLoggedCall200ResponseModelResponse {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof LocalTestingOnlyGetLatestLoggedCall200ResponseModelResponse
|
||||
*/
|
||||
'id': string;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof LocalTestingOnlyGetLatestLoggedCall200ResponseModelResponse
|
||||
*/
|
||||
'statusCode': number | null;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof LocalTestingOnlyGetLatestLoggedCall200ResponseModelResponse
|
||||
*/
|
||||
'errorMessage': string | null;
|
||||
/**
|
||||
*
|
||||
* @type {any}
|
||||
* @memberof LocalTestingOnlyGetLatestLoggedCall200ResponseModelResponse
|
||||
*/
|
||||
'reqPayload'?: any;
|
||||
/**
|
||||
*
|
||||
* @type {any}
|
||||
* @memberof LocalTestingOnlyGetLatestLoggedCall200ResponseModelResponse
|
||||
*/
|
||||
'respPayload'?: any;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface ReportRequest
|
||||
*/
|
||||
export interface ReportRequest {
|
||||
/**
|
||||
* Unix timestamp in milliseconds
|
||||
* @type {number}
|
||||
* @memberof ReportRequest
|
||||
*/
|
||||
'requestedAt': number;
|
||||
/**
|
||||
* Unix timestamp in milliseconds
|
||||
* @type {number}
|
||||
* @memberof ReportRequest
|
||||
*/
|
||||
'receivedAt': number;
|
||||
/**
|
||||
* JSON-encoded request payload
|
||||
* @type {any}
|
||||
* @memberof ReportRequest
|
||||
*/
|
||||
'reqPayload'?: any;
|
||||
/**
|
||||
* JSON-encoded response payload
|
||||
* @type {any}
|
||||
* @memberof ReportRequest
|
||||
*/
|
||||
'respPayload'?: any;
|
||||
/**
|
||||
* HTTP status code of response
|
||||
* @type {number}
|
||||
* @memberof ReportRequest
|
||||
*/
|
||||
'statusCode'?: number;
|
||||
/**
|
||||
* User-friendly error message
|
||||
* @type {string}
|
||||
* @memberof ReportRequest
|
||||
*/
|
||||
'errorMessage'?: string;
|
||||
/**
|
||||
* Extra tags to attach to the call for filtering. Eg { \"userId\": \"123\", \"promptId\": \"populate-title\" }
|
||||
* @type {{ [key: string]: string; }}
|
||||
* @memberof ReportRequest
|
||||
*/
|
||||
'tags'?: { [key: string]: string; };
|
||||
}
|
||||
|
||||
/**
|
||||
* DefaultApi - axios parameter creator
|
||||
* @export
|
||||
*/
|
||||
export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||
return {
|
||||
/**
|
||||
* Check if a prompt is cached
|
||||
* @param {CheckCacheRequest} checkCacheRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
checkCache: async (checkCacheRequest: CheckCacheRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'checkCacheRequest' is not null or undefined
|
||||
assertParamExists('checkCache', 'checkCacheRequest', checkCacheRequest)
|
||||
const localVarPath = `/check-cache`;
|
||||
// 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;
|
||||
|
||||
// authentication Authorization required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(checkCacheRequest, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Get the latest logged call (only for local testing)
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
localTestingOnlyGetLatestLoggedCall: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
const localVarPath = `/local-testing-only-get-latest-logged-call`;
|
||||
// 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: 'GET', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication Authorization required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Report an API call
|
||||
* @param {ReportRequest} reportRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
report: async (reportRequest: ReportRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'reportRequest' is not null or undefined
|
||||
assertParamExists('report', 'reportRequest', reportRequest)
|
||||
const localVarPath = `/report`;
|
||||
// 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;
|
||||
|
||||
// authentication Authorization required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(reportRequest, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* DefaultApi - functional programming interface
|
||||
* @export
|
||||
*/
|
||||
export const DefaultApiFp = function(configuration?: Configuration) {
|
||||
const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration)
|
||||
return {
|
||||
/**
|
||||
* Check if a prompt is cached
|
||||
* @param {CheckCacheRequest} checkCacheRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async checkCache(checkCacheRequest: CheckCacheRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<CheckCache200Response>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.checkCache(checkCacheRequest, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
* Get the latest logged call (only for local testing)
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async localTestingOnlyGetLatestLoggedCall(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<LocalTestingOnlyGetLatestLoggedCall200Response>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.localTestingOnlyGetLatestLoggedCall(options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
* Report an API call
|
||||
* @param {ReportRequest} reportRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async report(reportRequest: ReportRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<any>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.report(reportRequest, 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 {
|
||||
/**
|
||||
* Check if a prompt is cached
|
||||
* @param {CheckCacheRequest} checkCacheRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
checkCache(checkCacheRequest: CheckCacheRequest, options?: any): AxiosPromise<CheckCache200Response> {
|
||||
return localVarFp.checkCache(checkCacheRequest, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Get the latest logged call (only for local testing)
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
localTestingOnlyGetLatestLoggedCall(options?: any): AxiosPromise<LocalTestingOnlyGetLatestLoggedCall200Response> {
|
||||
return localVarFp.localTestingOnlyGetLatestLoggedCall(options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Report an API call
|
||||
* @param {ReportRequest} reportRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
report(reportRequest: ReportRequest, options?: any): AxiosPromise<any> {
|
||||
return localVarFp.report(reportRequest, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* DefaultApi - object-oriented interface
|
||||
* @export
|
||||
* @class DefaultApi
|
||||
* @extends {BaseAPI}
|
||||
*/
|
||||
export class DefaultApi extends BaseAPI {
|
||||
/**
|
||||
* Check if a prompt is cached
|
||||
* @param {CheckCacheRequest} checkCacheRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof DefaultApi
|
||||
*/
|
||||
public checkCache(checkCacheRequest: CheckCacheRequest, options?: AxiosRequestConfig) {
|
||||
return DefaultApiFp(this.configuration).checkCache(checkCacheRequest, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest logged call (only for local testing)
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof DefaultApi
|
||||
*/
|
||||
public localTestingOnlyGetLatestLoggedCall(options?: AxiosRequestConfig) {
|
||||
return DefaultApiFp(this.configuration).localTestingOnlyGetLatestLoggedCall(options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an API call
|
||||
* @param {ReportRequest} reportRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof DefaultApi
|
||||
*/
|
||||
public report(reportRequest: ReportRequest, options?: AxiosRequestConfig) {
|
||||
return DefaultApiFp(this.configuration).report(reportRequest, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* OpenPipe API
|
||||
* The public API for reporting API calls to OpenPipe
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.1
|
||||
*
|
||||
*
|
||||
* 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/v1".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"
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* OpenPipe API
|
||||
* The public API for reporting API calls to OpenPipe
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.1
|
||||
*
|
||||
*
|
||||
* 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);
|
||||
};
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* OpenPipe API
|
||||
* The public API for reporting API calls to OpenPipe
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.1
|
||||
*
|
||||
*
|
||||
* 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');
|
||||
}
|
||||
}
|
||||
25
client-libs/typescript/src/codegen/core/ApiError.ts
Normal file
25
client-libs/typescript/src/codegen/core/ApiError.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||
import type { ApiResult } from './ApiResult';
|
||||
|
||||
export class ApiError extends Error {
|
||||
public readonly url: string;
|
||||
public readonly status: number;
|
||||
public readonly statusText: string;
|
||||
public readonly body: any;
|
||||
public readonly request: ApiRequestOptions;
|
||||
|
||||
constructor(request: ApiRequestOptions, response: ApiResult, message: string) {
|
||||
super(message);
|
||||
|
||||
this.name = 'ApiError';
|
||||
this.url = response.url;
|
||||
this.status = response.status;
|
||||
this.statusText = response.statusText;
|
||||
this.body = response.body;
|
||||
this.request = request;
|
||||
}
|
||||
}
|
||||
17
client-libs/typescript/src/codegen/core/ApiRequestOptions.ts
Normal file
17
client-libs/typescript/src/codegen/core/ApiRequestOptions.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type ApiRequestOptions = {
|
||||
readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH';
|
||||
readonly url: string;
|
||||
readonly path?: Record<string, any>;
|
||||
readonly cookies?: Record<string, any>;
|
||||
readonly headers?: Record<string, any>;
|
||||
readonly query?: Record<string, any>;
|
||||
readonly formData?: Record<string, any>;
|
||||
readonly body?: any;
|
||||
readonly mediaType?: string;
|
||||
readonly responseHeader?: string;
|
||||
readonly errors?: Record<number, string>;
|
||||
};
|
||||
11
client-libs/typescript/src/codegen/core/ApiResult.ts
Normal file
11
client-libs/typescript/src/codegen/core/ApiResult.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type ApiResult = {
|
||||
readonly url: string;
|
||||
readonly ok: boolean;
|
||||
readonly status: number;
|
||||
readonly statusText: string;
|
||||
readonly body: any;
|
||||
};
|
||||
14
client-libs/typescript/src/codegen/core/BaseHttpRequest.ts
Normal file
14
client-libs/typescript/src/codegen/core/BaseHttpRequest.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||
import type { CancelablePromise } from './CancelablePromise';
|
||||
import type { OpenAPIConfig } from './OpenAPI';
|
||||
|
||||
export abstract class BaseHttpRequest {
|
||||
|
||||
constructor(public readonly config: OpenAPIConfig) {}
|
||||
|
||||
public abstract request<T>(options: ApiRequestOptions): CancelablePromise<T>;
|
||||
}
|
||||
131
client-libs/typescript/src/codegen/core/CancelablePromise.ts
Normal file
131
client-libs/typescript/src/codegen/core/CancelablePromise.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export class CancelError extends Error {
|
||||
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'CancelError';
|
||||
}
|
||||
|
||||
public get isCancelled(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export interface OnCancel {
|
||||
readonly isResolved: boolean;
|
||||
readonly isRejected: boolean;
|
||||
readonly isCancelled: boolean;
|
||||
|
||||
(cancelHandler: () => void): void;
|
||||
}
|
||||
|
||||
export class CancelablePromise<T> implements Promise<T> {
|
||||
#isResolved: boolean;
|
||||
#isRejected: boolean;
|
||||
#isCancelled: boolean;
|
||||
readonly #cancelHandlers: (() => void)[];
|
||||
readonly #promise: Promise<T>;
|
||||
#resolve?: (value: T | PromiseLike<T>) => void;
|
||||
#reject?: (reason?: any) => void;
|
||||
|
||||
constructor(
|
||||
executor: (
|
||||
resolve: (value: T | PromiseLike<T>) => void,
|
||||
reject: (reason?: any) => void,
|
||||
onCancel: OnCancel
|
||||
) => void
|
||||
) {
|
||||
this.#isResolved = false;
|
||||
this.#isRejected = false;
|
||||
this.#isCancelled = false;
|
||||
this.#cancelHandlers = [];
|
||||
this.#promise = new Promise<T>((resolve, reject) => {
|
||||
this.#resolve = resolve;
|
||||
this.#reject = reject;
|
||||
|
||||
const onResolve = (value: T | PromiseLike<T>): void => {
|
||||
if (this.#isResolved || this.#isRejected || this.#isCancelled) {
|
||||
return;
|
||||
}
|
||||
this.#isResolved = true;
|
||||
this.#resolve?.(value);
|
||||
};
|
||||
|
||||
const onReject = (reason?: any): void => {
|
||||
if (this.#isResolved || this.#isRejected || this.#isCancelled) {
|
||||
return;
|
||||
}
|
||||
this.#isRejected = true;
|
||||
this.#reject?.(reason);
|
||||
};
|
||||
|
||||
const onCancel = (cancelHandler: () => void): void => {
|
||||
if (this.#isResolved || this.#isRejected || this.#isCancelled) {
|
||||
return;
|
||||
}
|
||||
this.#cancelHandlers.push(cancelHandler);
|
||||
};
|
||||
|
||||
Object.defineProperty(onCancel, 'isResolved', {
|
||||
get: (): boolean => this.#isResolved,
|
||||
});
|
||||
|
||||
Object.defineProperty(onCancel, 'isRejected', {
|
||||
get: (): boolean => this.#isRejected,
|
||||
});
|
||||
|
||||
Object.defineProperty(onCancel, 'isCancelled', {
|
||||
get: (): boolean => this.#isCancelled,
|
||||
});
|
||||
|
||||
return executor(onResolve, onReject, onCancel as OnCancel);
|
||||
});
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag]() {
|
||||
return "Cancellable Promise";
|
||||
}
|
||||
|
||||
public then<TResult1 = T, TResult2 = never>(
|
||||
onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
|
||||
onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
|
||||
): Promise<TResult1 | TResult2> {
|
||||
return this.#promise.then(onFulfilled, onRejected);
|
||||
}
|
||||
|
||||
public catch<TResult = never>(
|
||||
onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null
|
||||
): Promise<T | TResult> {
|
||||
return this.#promise.catch(onRejected);
|
||||
}
|
||||
|
||||
public finally(onFinally?: (() => void) | null): Promise<T> {
|
||||
return this.#promise.finally(onFinally);
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
if (this.#isResolved || this.#isRejected || this.#isCancelled) {
|
||||
return;
|
||||
}
|
||||
this.#isCancelled = true;
|
||||
if (this.#cancelHandlers.length) {
|
||||
try {
|
||||
for (const cancelHandler of this.#cancelHandlers) {
|
||||
cancelHandler();
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Cancellation threw an error', error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.#cancelHandlers.length = 0;
|
||||
this.#reject?.(new CancelError('Request aborted'));
|
||||
}
|
||||
|
||||
public get isCancelled(): boolean {
|
||||
return this.#isCancelled;
|
||||
}
|
||||
}
|
||||
26
client-libs/typescript/src/codegen/core/NodeHttpRequest.ts
Normal file
26
client-libs/typescript/src/codegen/core/NodeHttpRequest.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||
import { BaseHttpRequest } from './BaseHttpRequest';
|
||||
import type { CancelablePromise } from './CancelablePromise';
|
||||
import type { OpenAPIConfig } from './OpenAPI';
|
||||
import { request as __request } from './request';
|
||||
|
||||
export class NodeHttpRequest extends BaseHttpRequest {
|
||||
|
||||
constructor(config: OpenAPIConfig) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request method
|
||||
* @param options The request options from the service
|
||||
* @returns CancelablePromise<T>
|
||||
* @throws ApiError
|
||||
*/
|
||||
public override request<T>(options: ApiRequestOptions): CancelablePromise<T> {
|
||||
return __request(this.config, options);
|
||||
}
|
||||
}
|
||||
32
client-libs/typescript/src/codegen/core/OpenAPI.ts
Normal file
32
client-libs/typescript/src/codegen/core/OpenAPI.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||
|
||||
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
|
||||
type Headers = Record<string, string>;
|
||||
|
||||
export type OpenAPIConfig = {
|
||||
BASE: string;
|
||||
VERSION: string;
|
||||
WITH_CREDENTIALS: boolean;
|
||||
CREDENTIALS: 'include' | 'omit' | 'same-origin';
|
||||
TOKEN?: string | Resolver<string> | undefined;
|
||||
USERNAME?: string | Resolver<string> | undefined;
|
||||
PASSWORD?: string | Resolver<string> | undefined;
|
||||
HEADERS?: Headers | Resolver<Headers> | undefined;
|
||||
ENCODE_PATH?: ((path: string) => string) | undefined;
|
||||
};
|
||||
|
||||
export const OpenAPI: OpenAPIConfig = {
|
||||
BASE: 'https://app.openpipe.ai/api/v1',
|
||||
VERSION: '0.1.1',
|
||||
WITH_CREDENTIALS: false,
|
||||
CREDENTIALS: 'include',
|
||||
TOKEN: undefined,
|
||||
USERNAME: undefined,
|
||||
PASSWORD: undefined,
|
||||
HEADERS: undefined,
|
||||
ENCODE_PATH: undefined,
|
||||
};
|
||||
341
client-libs/typescript/src/codegen/core/request.ts
Normal file
341
client-libs/typescript/src/codegen/core/request.ts
Normal file
@@ -0,0 +1,341 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import FormData from "form-data";
|
||||
import fetch, { Headers } from "node-fetch";
|
||||
import type { RequestInit, Response } from "node-fetch";
|
||||
|
||||
// @ts-expect-error TODO maybe I need an older node-fetch or something?
|
||||
import type { AbortSignal } from "node-fetch/externals";
|
||||
|
||||
import { ApiError } from "./ApiError";
|
||||
import type { ApiRequestOptions } from "./ApiRequestOptions";
|
||||
import type { ApiResult } from "./ApiResult";
|
||||
import { CancelablePromise } from "./CancelablePromise";
|
||||
import type { OnCancel } from "./CancelablePromise";
|
||||
import type { OpenAPIConfig } from "./OpenAPI";
|
||||
|
||||
export const isDefined = <T>(
|
||||
value: T | null | undefined
|
||||
): value is Exclude<T, null | undefined> => {
|
||||
return value !== undefined && value !== null;
|
||||
};
|
||||
|
||||
export const isString = (value: any): value is string => {
|
||||
return typeof value === "string";
|
||||
};
|
||||
|
||||
export const isStringWithValue = (value: any): value is string => {
|
||||
return isString(value) && value !== "";
|
||||
};
|
||||
|
||||
export const isBlob = (value: any): value is Blob => {
|
||||
return (
|
||||
typeof value === "object" &&
|
||||
typeof value.type === "string" &&
|
||||
typeof value.stream === "function" &&
|
||||
typeof value.arrayBuffer === "function" &&
|
||||
typeof value.constructor === "function" &&
|
||||
typeof value.constructor.name === "string" &&
|
||||
/^(Blob|File)$/.test(value.constructor.name) &&
|
||||
/^(Blob|File)$/.test(value[Symbol.toStringTag])
|
||||
);
|
||||
};
|
||||
|
||||
export const isFormData = (value: any): value is FormData => {
|
||||
return value instanceof FormData;
|
||||
};
|
||||
|
||||
export const base64 = (str: string): string => {
|
||||
try {
|
||||
return btoa(str);
|
||||
} catch (err) {
|
||||
// @ts-ignore
|
||||
return Buffer.from(str).toString("base64");
|
||||
}
|
||||
};
|
||||
|
||||
export const getQueryString = (params: Record<string, any>): string => {
|
||||
const qs: string[] = [];
|
||||
|
||||
const append = (key: string, value: any) => {
|
||||
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
||||
};
|
||||
|
||||
const process = (key: string, value: any) => {
|
||||
if (isDefined(value)) {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((v) => {
|
||||
process(key, v);
|
||||
});
|
||||
} else if (typeof value === "object") {
|
||||
Object.entries(value).forEach(([k, v]) => {
|
||||
process(`${key}[${k}]`, v);
|
||||
});
|
||||
} else {
|
||||
append(key, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
process(key, value);
|
||||
});
|
||||
|
||||
if (qs.length > 0) {
|
||||
return `?${qs.join("&")}`;
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => {
|
||||
const encoder = config.ENCODE_PATH || encodeURI;
|
||||
|
||||
const path = options.url
|
||||
.replace("{api-version}", config.VERSION)
|
||||
.replace(/{(.*?)}/g, (substring: string, group: string) => {
|
||||
if (options.path?.hasOwnProperty(group)) {
|
||||
return encoder(String(options.path[group]));
|
||||
}
|
||||
return substring;
|
||||
});
|
||||
|
||||
const url = `${config.BASE}${path}`;
|
||||
if (options.query) {
|
||||
return `${url}${getQueryString(options.query)}`;
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
export const getFormData = (options: ApiRequestOptions): FormData | undefined => {
|
||||
if (options.formData) {
|
||||
const formData = new FormData();
|
||||
|
||||
const process = (key: string, value: any) => {
|
||||
if (isString(value) || isBlob(value)) {
|
||||
formData.append(key, value);
|
||||
} else {
|
||||
formData.append(key, JSON.stringify(value));
|
||||
}
|
||||
};
|
||||
|
||||
Object.entries(options.formData)
|
||||
.filter(([_, value]) => isDefined(value))
|
||||
.forEach(([key, value]) => {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((v) => process(key, v));
|
||||
} else {
|
||||
process(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
return formData;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
|
||||
|
||||
export const resolve = async <T>(
|
||||
options: ApiRequestOptions,
|
||||
resolver?: T | Resolver<T>
|
||||
): Promise<T | undefined> => {
|
||||
if (typeof resolver === "function") {
|
||||
return (resolver as Resolver<T>)(options);
|
||||
}
|
||||
return resolver;
|
||||
};
|
||||
|
||||
export const getHeaders = async (
|
||||
config: OpenAPIConfig,
|
||||
options: ApiRequestOptions
|
||||
): Promise<Headers> => {
|
||||
const token = await resolve(options, config.TOKEN);
|
||||
const username = await resolve(options, config.USERNAME);
|
||||
const password = await resolve(options, config.PASSWORD);
|
||||
const additionalHeaders = await resolve(options, config.HEADERS);
|
||||
|
||||
const headers = Object.entries({
|
||||
Accept: "application/json",
|
||||
...additionalHeaders,
|
||||
...options.headers,
|
||||
})
|
||||
.filter(([_, value]) => isDefined(value))
|
||||
.reduce(
|
||||
(headers, [key, value]) => ({
|
||||
...headers,
|
||||
[key]: String(value),
|
||||
}),
|
||||
{} as Record<string, string>
|
||||
);
|
||||
|
||||
if (isStringWithValue(token)) {
|
||||
headers["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
if (isStringWithValue(username) && isStringWithValue(password)) {
|
||||
const credentials = base64(`${username}:${password}`);
|
||||
headers["Authorization"] = `Basic ${credentials}`;
|
||||
}
|
||||
|
||||
if (options.body) {
|
||||
if (options.mediaType) {
|
||||
headers["Content-Type"] = options.mediaType;
|
||||
} else if (isBlob(options.body)) {
|
||||
headers["Content-Type"] = "application/octet-stream";
|
||||
} else if (isString(options.body)) {
|
||||
headers["Content-Type"] = "text/plain";
|
||||
} else if (!isFormData(options.body)) {
|
||||
headers["Content-Type"] = "application/json";
|
||||
}
|
||||
}
|
||||
|
||||
return new Headers(headers);
|
||||
};
|
||||
|
||||
export const getRequestBody = (options: ApiRequestOptions): any => {
|
||||
if (options.body !== undefined) {
|
||||
if (options.mediaType?.includes("/json")) {
|
||||
return JSON.stringify(options.body);
|
||||
} else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) {
|
||||
return options.body as any;
|
||||
} else {
|
||||
return JSON.stringify(options.body);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const sendRequest = async (
|
||||
options: ApiRequestOptions,
|
||||
url: string,
|
||||
body: any,
|
||||
formData: FormData | undefined,
|
||||
headers: Headers,
|
||||
onCancel: OnCancel
|
||||
): Promise<Response> => {
|
||||
const controller = new AbortController();
|
||||
|
||||
const request: RequestInit = {
|
||||
headers,
|
||||
method: options.method,
|
||||
body: body ?? formData,
|
||||
signal: controller.signal as AbortSignal,
|
||||
};
|
||||
|
||||
onCancel(() => controller.abort());
|
||||
|
||||
return await fetch(url, request);
|
||||
};
|
||||
|
||||
export const getResponseHeader = (
|
||||
response: Response,
|
||||
responseHeader?: string
|
||||
): string | undefined => {
|
||||
if (responseHeader) {
|
||||
const content = response.headers.get(responseHeader);
|
||||
if (isString(content)) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const getResponseBody = async (response: Response): Promise<any> => {
|
||||
if (response.status !== 204) {
|
||||
try {
|
||||
const contentType = response.headers.get("Content-Type");
|
||||
if (contentType) {
|
||||
const jsonTypes = ["application/json", "application/problem+json"];
|
||||
const isJSON = jsonTypes.some((type) => contentType.toLowerCase().startsWith(type));
|
||||
if (isJSON) {
|
||||
return await response.json();
|
||||
} else {
|
||||
return await response.text();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): void => {
|
||||
const errors: Record<number, string> = {
|
||||
400: "Bad Request",
|
||||
401: "Unauthorized",
|
||||
403: "Forbidden",
|
||||
404: "Not Found",
|
||||
500: "Internal Server Error",
|
||||
502: "Bad Gateway",
|
||||
503: "Service Unavailable",
|
||||
...options.errors,
|
||||
};
|
||||
|
||||
const error = errors[result.status];
|
||||
if (error) {
|
||||
throw new ApiError(options, result, error);
|
||||
}
|
||||
|
||||
if (!result.ok) {
|
||||
const errorStatus = result.status ?? "unknown";
|
||||
const errorStatusText = result.statusText ?? "unknown";
|
||||
const errorBody = (() => {
|
||||
try {
|
||||
return JSON.stringify(result.body, null, 2);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
})();
|
||||
|
||||
throw new ApiError(
|
||||
options,
|
||||
result,
|
||||
`Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Request method
|
||||
* @param config The OpenAPI configuration object
|
||||
* @param options The request options from the service
|
||||
* @returns CancelablePromise<T>
|
||||
* @throws ApiError
|
||||
*/
|
||||
export const request = <T>(
|
||||
config: OpenAPIConfig,
|
||||
options: ApiRequestOptions
|
||||
): CancelablePromise<T> => {
|
||||
return new CancelablePromise(async (resolve, reject, onCancel) => {
|
||||
try {
|
||||
const url = getUrl(config, options);
|
||||
const formData = getFormData(options);
|
||||
const body = getRequestBody(options);
|
||||
const headers = await getHeaders(config, options);
|
||||
|
||||
if (!onCancel.isCancelled) {
|
||||
const response = await sendRequest(options, url, body, formData, headers, onCancel);
|
||||
const responseBody = await getResponseBody(response);
|
||||
const responseHeader = getResponseHeader(response, options.responseHeader);
|
||||
|
||||
const result: ApiResult = {
|
||||
url,
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
body: responseHeader ?? responseBody,
|
||||
};
|
||||
|
||||
catchErrorCodes(options, result);
|
||||
|
||||
resolve(result.body);
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
#!/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'
|
||||
@@ -1,18 +1,13 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* OpenPipe API
|
||||
* The public API for reporting API calls to OpenPipe
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.1
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
export { OPClient } from './OPClient';
|
||||
|
||||
export { ApiError } from './core/ApiError';
|
||||
export { BaseHttpRequest } from './core/BaseHttpRequest';
|
||||
export { CancelablePromise, CancelError } from './core/CancelablePromise';
|
||||
export { OpenAPI } from './core/OpenAPI';
|
||||
export type { OpenAPIConfig } from './core/OpenAPI';
|
||||
|
||||
export * from "./api";
|
||||
export * from "./configuration";
|
||||
|
||||
export { DefaultService } from './services/DefaultService';
|
||||
|
||||
118
client-libs/typescript/src/codegen/services/DefaultService.ts
Normal file
118
client-libs/typescript/src/codegen/services/DefaultService.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { CancelablePromise } from '../core/CancelablePromise';
|
||||
import type { BaseHttpRequest } from '../core/BaseHttpRequest';
|
||||
|
||||
export class DefaultService {
|
||||
|
||||
constructor(public readonly httpRequest: BaseHttpRequest) {}
|
||||
|
||||
/**
|
||||
* Check if a prompt is cached
|
||||
* @param requestBody
|
||||
* @returns any Successful response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public checkCache(
|
||||
requestBody: {
|
||||
/**
|
||||
* Unix timestamp in milliseconds
|
||||
*/
|
||||
requestedAt: number;
|
||||
/**
|
||||
* JSON-encoded request payload
|
||||
*/
|
||||
reqPayload?: any;
|
||||
/**
|
||||
* Extra tags to attach to the call for filtering. Eg { "userId": "123", "promptId": "populate-title" }
|
||||
*/
|
||||
tags?: Record<string, string>;
|
||||
},
|
||||
): CancelablePromise<{
|
||||
/**
|
||||
* JSON-encoded response payload
|
||||
*/
|
||||
respPayload?: any;
|
||||
}> {
|
||||
return this.httpRequest.request({
|
||||
method: 'POST',
|
||||
url: '/check-cache',
|
||||
body: requestBody,
|
||||
mediaType: 'application/json',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an API call
|
||||
* @param requestBody
|
||||
* @returns any Successful response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public report(
|
||||
requestBody: {
|
||||
/**
|
||||
* Unix timestamp in milliseconds
|
||||
*/
|
||||
requestedAt: number;
|
||||
/**
|
||||
* Unix timestamp in milliseconds
|
||||
*/
|
||||
receivedAt: number;
|
||||
/**
|
||||
* JSON-encoded request payload
|
||||
*/
|
||||
reqPayload?: any;
|
||||
/**
|
||||
* JSON-encoded response payload
|
||||
*/
|
||||
respPayload?: any;
|
||||
/**
|
||||
* HTTP status code of response
|
||||
*/
|
||||
statusCode?: number;
|
||||
/**
|
||||
* User-friendly error message
|
||||
*/
|
||||
errorMessage?: string;
|
||||
/**
|
||||
* Extra tags to attach to the call for filtering. Eg { "userId": "123", "promptId": "populate-title" }
|
||||
*/
|
||||
tags?: Record<string, string>;
|
||||
},
|
||||
): CancelablePromise<{
|
||||
status: 'ok';
|
||||
}> {
|
||||
return this.httpRequest.request({
|
||||
method: 'POST',
|
||||
url: '/report',
|
||||
body: requestBody,
|
||||
mediaType: 'application/json',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest logged call (only for local testing)
|
||||
* @returns any Successful response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public localTestingOnlyGetLatestLoggedCall(): CancelablePromise<{
|
||||
createdAt: string;
|
||||
cacheHit: boolean;
|
||||
tags: Record<string, string | null>;
|
||||
modelResponse: {
|
||||
id: string;
|
||||
statusCode: number | null;
|
||||
errorMessage: string | null;
|
||||
reqPayload?: any;
|
||||
respPayload?: any;
|
||||
} | null;
|
||||
} | null> {
|
||||
return this.httpRequest.request({
|
||||
method: 'GET',
|
||||
url: '/local-testing-only-get-latest-logged-call',
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,90 +1,85 @@
|
||||
// import * as openPipeClient from "../codegen";
|
||||
// import * as openai from "openai-legacy";
|
||||
// import { version } from "../package.json";
|
||||
import * as openPipeClient from "../codegen";
|
||||
import * as openai from "openai-legacy";
|
||||
import { version } from "../../package.json";
|
||||
|
||||
// // Anything we don't override we want to pass through to openai directly
|
||||
// export * as openAILegacy from "openai-legacy";
|
||||
// Anything we don't override we want to pass through to openai directly
|
||||
export * as openAILegacy from "openai-legacy";
|
||||
|
||||
// type OPConfigurationParameters = {
|
||||
// apiKey?: string;
|
||||
// basePath?: string;
|
||||
// };
|
||||
type OPConfigurationParameters = {
|
||||
apiKey?: string;
|
||||
basePath?: string;
|
||||
};
|
||||
|
||||
// export class Configuration extends openai.Configuration {
|
||||
// public qkConfig?: openPipeClient.Configuration;
|
||||
export class Configuration extends openai.Configuration {
|
||||
public qkConfig?: openPipeClient.Configuration;
|
||||
|
||||
// constructor(
|
||||
// config: openai.ConfigurationParameters & {
|
||||
// opParameters?: OPConfigurationParameters;
|
||||
// }
|
||||
// ) {
|
||||
// super(config);
|
||||
// if (config.opParameters) {
|
||||
// this.qkConfig = new openPipeClient.Configuration(config.opParameters);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
constructor(
|
||||
config: openai.ConfigurationParameters & {
|
||||
opParameters?: OPConfigurationParameters;
|
||||
}
|
||||
) {
|
||||
super(config);
|
||||
if (config.opParameters) {
|
||||
this.qkConfig = new openPipeClient.Configuration(config.opParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// type CreateChatCompletion = InstanceType<
|
||||
// typeof openai.OpenAIApi
|
||||
// >["createChatCompletion"];
|
||||
type CreateChatCompletion = InstanceType<typeof openai.OpenAIApi>["createChatCompletion"];
|
||||
|
||||
// export class OpenAIApi extends openai.OpenAIApi {
|
||||
// public openPipeApi?: openPipeClient.DefaultApi;
|
||||
export class OpenAIApi extends openai.OpenAIApi {
|
||||
public openPipeApi?: openPipeClient.DefaultApi;
|
||||
|
||||
// constructor(config: Configuration) {
|
||||
// super(config);
|
||||
// if (config.qkConfig) {
|
||||
// this.openPipeApi = new openPipeClient.DefaultApi(config.qkConfig);
|
||||
// }
|
||||
// }
|
||||
constructor(config: Configuration) {
|
||||
super(config);
|
||||
if (config.qkConfig) {
|
||||
this.openPipeApi = new openPipeClient.DefaultApi(config.qkConfig);
|
||||
}
|
||||
}
|
||||
|
||||
// public async createChatCompletion(
|
||||
// createChatCompletionRequest: Parameters<CreateChatCompletion>[0],
|
||||
// options?: Parameters<CreateChatCompletion>[1]
|
||||
// ): ReturnType<CreateChatCompletion> {
|
||||
// const requestedAt = Date.now();
|
||||
// let resp: Awaited<ReturnType<CreateChatCompletion>> | null = null;
|
||||
// let respPayload: openai.CreateChatCompletionResponse | null = null;
|
||||
// let statusCode: number | undefined = undefined;
|
||||
// let errorMessage: string | undefined;
|
||||
// try {
|
||||
// resp = await super.createChatCompletion(
|
||||
// createChatCompletionRequest,
|
||||
// options
|
||||
// );
|
||||
// respPayload = resp.data;
|
||||
// statusCode = resp.status;
|
||||
// } catch (err) {
|
||||
// console.error("Error in createChatCompletion");
|
||||
// if ("isAxiosError" in err && err.isAxiosError) {
|
||||
// errorMessage = err.response?.data?.error?.message;
|
||||
// respPayload = err.response?.data;
|
||||
// statusCode = err.response?.status;
|
||||
// } else if ("message" in err) {
|
||||
// errorMessage = err.message.toString();
|
||||
// }
|
||||
// throw err;
|
||||
// } finally {
|
||||
// this.openPipeApi
|
||||
// ?.externalApiReport({
|
||||
// requestedAt,
|
||||
// receivedAt: Date.now(),
|
||||
// reqPayload: createChatCompletionRequest,
|
||||
// respPayload: respPayload,
|
||||
// statusCode: statusCode,
|
||||
// errorMessage,
|
||||
// tags: {
|
||||
// client: "openai-js",
|
||||
// clientVersion: version,
|
||||
// },
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// console.error("Error reporting to OP", err);
|
||||
// });
|
||||
// }
|
||||
public async createChatCompletion(
|
||||
createChatCompletionRequest: Parameters<CreateChatCompletion>[0],
|
||||
options?: Parameters<CreateChatCompletion>[1]
|
||||
): ReturnType<CreateChatCompletion> {
|
||||
const requestedAt = Date.now();
|
||||
let resp: Awaited<ReturnType<CreateChatCompletion>> | null = null;
|
||||
let respPayload: openai.CreateChatCompletionResponse | null = null;
|
||||
let statusCode: number | undefined = undefined;
|
||||
let errorMessage: string | undefined;
|
||||
try {
|
||||
resp = await super.createChatCompletion(createChatCompletionRequest, options);
|
||||
respPayload = resp.data;
|
||||
statusCode = resp.status;
|
||||
} catch (err) {
|
||||
console.error("Error in createChatCompletion");
|
||||
if ("isAxiosError" in err && err.isAxiosError) {
|
||||
errorMessage = err.response?.data?.error?.message;
|
||||
respPayload = err.response?.data;
|
||||
statusCode = err.response?.status;
|
||||
} else if ("message" in err) {
|
||||
errorMessage = err.message.toString();
|
||||
}
|
||||
throw err;
|
||||
} finally {
|
||||
this.openPipeApi
|
||||
?.externalApiReport({
|
||||
requestedAt,
|
||||
receivedAt: Date.now(),
|
||||
reqPayload: createChatCompletionRequest,
|
||||
respPayload: respPayload,
|
||||
statusCode: statusCode,
|
||||
errorMessage,
|
||||
tags: {
|
||||
client: "openai-js",
|
||||
clientVersion: version,
|
||||
},
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Error reporting to OP", err);
|
||||
});
|
||||
}
|
||||
|
||||
// console.log("done");
|
||||
// return resp;
|
||||
// }
|
||||
// }
|
||||
console.log("done");
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
|
||||
126
client-libs/typescript/src/openai/index.test.ts
Normal file
126
client-libs/typescript/src/openai/index.test.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import dotenv from "dotenv";
|
||||
import { expect, test } from "vitest";
|
||||
import OpenAI from ".";
|
||||
import {
|
||||
CompletionCreateParams,
|
||||
CreateChatCompletionRequestMessage,
|
||||
} from "openai-beta/resources/chat/completions";
|
||||
import { OPClient } from "../codegen";
|
||||
|
||||
dotenv.config({ path: "../.env" });
|
||||
|
||||
const oaiClient = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
openpipe: {
|
||||
apiKey: process.env.OPENPIPE_API_KEY,
|
||||
baseUrl: "http://localhost:3000/api/v1",
|
||||
},
|
||||
});
|
||||
|
||||
const opClient = new OPClient({
|
||||
BASE: "http://localhost:3000/api/v1",
|
||||
TOKEN: process.env.OPENPIPE_API_KEY,
|
||||
});
|
||||
|
||||
const lastLoggedCall = async () => opClient.default.localTestingOnlyGetLatestLoggedCall();
|
||||
|
||||
test("basic call", async () => {
|
||||
const payload: CompletionCreateParams = {
|
||||
model: "gpt-3.5-turbo",
|
||||
messages: [{ role: "system", content: "count to 3" }],
|
||||
};
|
||||
const completion = await oaiClient.chat.completions.create({
|
||||
...payload,
|
||||
openpipe: {
|
||||
tags: { promptId: "test" },
|
||||
},
|
||||
});
|
||||
await completion.openpipe.reportingFinished;
|
||||
const lastLogged = await lastLoggedCall();
|
||||
expect(lastLogged?.modelResponse?.reqPayload).toMatchObject(payload);
|
||||
expect(completion).toMatchObject(lastLogged?.modelResponse?.respPayload);
|
||||
expect(lastLogged?.tags).toMatchObject({ promptId: "test" });
|
||||
});
|
||||
|
||||
const randomString = (length: number) => {
|
||||
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
return Array.from(
|
||||
{ length },
|
||||
() => characters[Math.floor(Math.random() * characters.length)]
|
||||
).join("");
|
||||
};
|
||||
|
||||
test.skip("streaming", async () => {
|
||||
const completion = await oaiClient.chat.completions.create({
|
||||
model: "gpt-3.5-turbo",
|
||||
messages: [{ role: "system", content: "count to 4" }],
|
||||
stream: true,
|
||||
});
|
||||
|
||||
let merged = null;
|
||||
for await (const chunk of completion) {
|
||||
merged = merge_openai_chunks(merged, chunk);
|
||||
}
|
||||
|
||||
const lastLogged = await lastLoggedCall();
|
||||
expect(lastLogged?.modelResponse?.respPayload.choices[0].message.content).toBe(
|
||||
merged.choices[0].message.content
|
||||
);
|
||||
});
|
||||
|
||||
test.skip("bad call streaming", async () => {
|
||||
try {
|
||||
await oaiClient.chat.completions.create({
|
||||
model: "gpt-3.5-turbo-blaster",
|
||||
messages: [{ role: "system", content: "count to 10" }],
|
||||
stream: true,
|
||||
});
|
||||
} catch (e) {
|
||||
const lastLogged = await lastLoggedCall();
|
||||
expect(lastLogged?.modelResponse?.errorMessage).toBe(
|
||||
"The model `gpt-3.5-turbo-blaster` does not exist"
|
||||
);
|
||||
expect(lastLogged?.modelResponse?.statusCode).toBe(404);
|
||||
}
|
||||
});
|
||||
|
||||
test("bad call", async () => {
|
||||
try {
|
||||
await oaiClient.chat.completions.create({
|
||||
model: "gpt-3.5-turbo-booster",
|
||||
messages: [{ role: "system", content: "count to 10" }],
|
||||
});
|
||||
} catch (e) {
|
||||
const lastLogged = await lastLoggedCall();
|
||||
expect(lastLogged?.modelResponse?.errorMessage).toBe(
|
||||
"The model `gpt-3.5-turbo-booster` does not exist"
|
||||
);
|
||||
expect(lastLogged?.modelResponse?.statusCode).toBe(404);
|
||||
}
|
||||
});
|
||||
|
||||
test("caching", async () => {
|
||||
const message: CreateChatCompletionRequestMessage = {
|
||||
role: "system",
|
||||
content: `repeat '${randomString(10)}'`,
|
||||
};
|
||||
const completion = await oaiClient.chat.completions.create({
|
||||
model: "gpt-3.5-turbo",
|
||||
messages: [message],
|
||||
openpipe: { cache: true },
|
||||
});
|
||||
expect(completion.openpipe.cacheStatus).toBe("MISS");
|
||||
|
||||
await completion.openpipe.reportingFinished;
|
||||
const firstLogged = await lastLoggedCall();
|
||||
expect(completion.choices[0].message.content).toBe(
|
||||
firstLogged?.modelResponse?.respPayload.choices[0].message.content
|
||||
);
|
||||
|
||||
const completion2 = await oaiClient.chat.completions.create({
|
||||
model: "gpt-3.5-turbo",
|
||||
messages: [message],
|
||||
openpipe: { cache: true },
|
||||
});
|
||||
expect(completion2.openpipe.cacheStatus).toBe("HIT");
|
||||
});
|
||||
@@ -1,109 +1,154 @@
|
||||
import * as openai from "openai-beta";
|
||||
import * as Core from "openai-beta/core";
|
||||
import { readEnv, type RequestOptions } from "openai-beta/core";
|
||||
import { CompletionCreateParams } from "openai-beta/resources/chat/completions";
|
||||
import axios from "axios";
|
||||
import {
|
||||
ChatCompletion,
|
||||
ChatCompletionChunk,
|
||||
CompletionCreateParams,
|
||||
Completions,
|
||||
} from "openai-beta/resources/chat/completions";
|
||||
|
||||
import * as openPipeClient from "../codegen";
|
||||
|
||||
interface ClientOptions extends openai.ClientOptions {
|
||||
openPipeApiKey?: string;
|
||||
openPipeBaseUrl?: string;
|
||||
}
|
||||
import { DefaultService, OPClient } from "../codegen";
|
||||
import { Stream } from "openai-beta/streaming";
|
||||
import { OpenPipeArgs, OpenPipeMeta, type OpenPipeConfig, getTags } from "../shared";
|
||||
|
||||
export type ClientOptions = openai.ClientOptions & { openpipe?: OpenPipeConfig };
|
||||
export default class OpenAI extends openai.OpenAI {
|
||||
public openPipeApi?: openPipeClient.DefaultApi;
|
||||
public opClient?: OPClient;
|
||||
|
||||
constructor({
|
||||
openPipeApiKey = readEnv("OPENPIPE_API_KEY"),
|
||||
openPipeBaseUrl = readEnv("OPENPIPE_BASE_URL") ?? `https://app.openpipe.ai/v1`,
|
||||
...opts
|
||||
}: ClientOptions = {}) {
|
||||
super({ ...opts });
|
||||
constructor({ openpipe, ...options }: ClientOptions = {}) {
|
||||
super({ ...options });
|
||||
|
||||
const openPipeApiKey = openpipe?.apiKey ?? readEnv("OPENPIPE_API_KEY");
|
||||
|
||||
if (openPipeApiKey) {
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: openPipeBaseUrl,
|
||||
headers: {
|
||||
Authorization: `Bearer ${openPipeApiKey}`,
|
||||
},
|
||||
});
|
||||
this.openPipeApi = new openPipeClient.DefaultApi(
|
||||
new openPipeClient.Configuration({
|
||||
apiKey: openPipeApiKey,
|
||||
basePath: openPipeBaseUrl,
|
||||
}),
|
||||
undefined,
|
||||
axiosInstance
|
||||
this.chat.setClient(
|
||||
new OPClient({
|
||||
BASE:
|
||||
openpipe?.baseUrl ?? readEnv("OPENPIPE_BASE_URL") ?? "https://app.openpipe.ai/api/v1",
|
||||
TOKEN: openPipeApiKey,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Override the chat property
|
||||
this.chat = new ExtendedChat(this);
|
||||
|
||||
if (openPipeApiKey === undefined) {
|
||||
console.error(
|
||||
"The OPENPIPE_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenPipe client with an openPipeApiKey option, like new OpenPipe({ openPipeApiKey: undefined })."
|
||||
} else {
|
||||
console.warn(
|
||||
"You're using the OpenPipe client without an API key. No completion requests will be logged."
|
||||
);
|
||||
}
|
||||
}
|
||||
chat: WrappedChat = new WrappedChat(this);
|
||||
}
|
||||
|
||||
class ExtendedChat extends openai.OpenAI.Chat {
|
||||
completions: ExtendedCompletions;
|
||||
|
||||
constructor(openaiInstance: OpenAI) {
|
||||
super(openaiInstance);
|
||||
// Initialize the new completions instance
|
||||
this.completions = new ExtendedCompletions(openaiInstance);
|
||||
class WrappedChat extends openai.OpenAI.Chat {
|
||||
setClient(client: OPClient) {
|
||||
this.completions.opClient = client;
|
||||
}
|
||||
|
||||
completions: InstrumentedCompletions = new InstrumentedCompletions(this.client);
|
||||
}
|
||||
|
||||
class ExtendedCompletions extends openai.OpenAI.Chat.Completions {
|
||||
private openaiInstance: OpenAI;
|
||||
class InstrumentedCompletions extends openai.OpenAI.Chat.Completions {
|
||||
opClient?: OPClient;
|
||||
|
||||
constructor(openaiInstance: OpenAI) {
|
||||
super(openaiInstance);
|
||||
this.openaiInstance = openaiInstance;
|
||||
constructor(client: openai.OpenAI, opClient?: OPClient) {
|
||||
super(client);
|
||||
this.opClient = opClient;
|
||||
}
|
||||
|
||||
_report(args: Parameters<DefaultService["report"]>[0]) {
|
||||
try {
|
||||
return this.opClient ? this.opClient.default.report(args) : Promise.resolve();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
create(
|
||||
body: CompletionCreateParams.CreateChatCompletionRequestNonStreaming & OpenPipeArgs,
|
||||
options?: Core.RequestOptions
|
||||
): Promise<Core.APIResponse<ChatCompletion & { openpipe: OpenPipeMeta }>>;
|
||||
create(
|
||||
body: CompletionCreateParams.CreateChatCompletionRequestStreaming & OpenPipeArgs,
|
||||
options?: Core.RequestOptions
|
||||
): Promise<Core.APIResponse<Stream<ChatCompletionChunk>>>;
|
||||
async create(
|
||||
params:
|
||||
| CompletionCreateParams.CreateChatCompletionRequestNonStreaming
|
||||
| CompletionCreateParams.CreateChatCompletionRequestStreaming,
|
||||
options?: RequestOptions,
|
||||
tags?: Record<string, string>
|
||||
): Promise<any> {
|
||||
// // Your pre API call logic here
|
||||
// console.log("Doing pre API call...");
|
||||
{ openpipe, ...body }: CompletionCreateParams & OpenPipeArgs,
|
||||
options?: Core.RequestOptions
|
||||
): Promise<
|
||||
Core.APIResponse<(ChatCompletion & { openpipe: OpenPipeMeta }) | Stream<ChatCompletionChunk>>
|
||||
> {
|
||||
console.log("LALALA REPORT", this.opClient);
|
||||
const requestedAt = Date.now();
|
||||
const cacheRequested = openpipe?.cache ?? false;
|
||||
|
||||
// // Determine the type of request
|
||||
// if (params.hasOwnProperty("stream") && params.stream === true) {
|
||||
// const result = await super.create(
|
||||
// params as CompletionCreateParams.CreateChatCompletionRequestStreaming,
|
||||
// options
|
||||
// );
|
||||
// // Your post API call logic here
|
||||
// console.log("Doing post API call for Streaming...");
|
||||
// return result;
|
||||
// } else {
|
||||
// const requestedAt = Date.now();
|
||||
const result = await super.create(
|
||||
params as CompletionCreateParams.CreateChatCompletionRequestNonStreaming,
|
||||
options
|
||||
);
|
||||
return result;
|
||||
// await this.openaiInstance.openPipeApi?.externalApiReport({
|
||||
// requestedAt,
|
||||
// receivedAt: Date.now(),
|
||||
// reqPayload: params,
|
||||
// respPayload: result,
|
||||
// statusCode: 200,
|
||||
// errorMessage: undefined,
|
||||
// tags,
|
||||
// });
|
||||
if (cacheRequested) {
|
||||
try {
|
||||
const cached = await this.opClient?.default
|
||||
.checkCache({
|
||||
requestedAt,
|
||||
reqPayload: body,
|
||||
tags: getTags(openpipe),
|
||||
})
|
||||
.then((res) => res.respPayload);
|
||||
|
||||
// console.log("GOT RESULT", result);
|
||||
// return result;
|
||||
// }
|
||||
if (cached) {
|
||||
return {
|
||||
...cached,
|
||||
openpipe: {
|
||||
cacheStatus: "HIT",
|
||||
reportingFinished: Promise.resolve(),
|
||||
},
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
let reportingFinished: OpenPipeMeta["reportingFinished"] = Promise.resolve();
|
||||
|
||||
try {
|
||||
if (body.stream) {
|
||||
const stream = await super.create(body, options);
|
||||
|
||||
// Do some logging of each chunk here
|
||||
|
||||
return stream;
|
||||
} else {
|
||||
const response = await super.create(body, options);
|
||||
|
||||
reportingFinished = this._report({
|
||||
requestedAt,
|
||||
receivedAt: Date.now(),
|
||||
reqPayload: body,
|
||||
respPayload: response,
|
||||
statusCode: 200,
|
||||
tags: getTags(openpipe),
|
||||
});
|
||||
return {
|
||||
...response,
|
||||
openpipe: {
|
||||
cacheStatus: cacheRequested ? "MISS" : "SKIP",
|
||||
reportingFinished,
|
||||
},
|
||||
};
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof openai.APIError) {
|
||||
const rawMessage = error.message as string | string[];
|
||||
const message = Array.isArray(rawMessage) ? rawMessage.join(", ") : rawMessage;
|
||||
reportingFinished = this._report({
|
||||
requestedAt,
|
||||
receivedAt: Date.now(),
|
||||
reqPayload: body,
|
||||
respPayload: error.error,
|
||||
statusCode: error.status,
|
||||
errorMessage: message,
|
||||
tags: getTags(openpipe),
|
||||
});
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
42
client-libs/typescript/src/openai/mergeChunks.ts
Normal file
42
client-libs/typescript/src/openai/mergeChunks.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { ChatCompletion, ChatCompletionChunk } from "openai-beta/resources/chat";
|
||||
|
||||
export default function mergeChunks(
|
||||
base: ChatCompletion | null,
|
||||
chunk: ChatCompletionChunk
|
||||
): ChatCompletion {
|
||||
if (base === null) {
|
||||
return mergeChunks({ ...chunk, choices: [] }, chunk);
|
||||
}
|
||||
|
||||
const choices = [...base.choices];
|
||||
for (const choice of chunk.choices) {
|
||||
const baseChoice = choices.find((c) => c.index === choice.index);
|
||||
if (baseChoice) {
|
||||
baseChoice.finish_reason = choice.finish_reason ?? baseChoice.finish_reason;
|
||||
baseChoice.message = baseChoice.message ?? { role: "assistant" };
|
||||
|
||||
if (choice.delta?.content)
|
||||
baseChoice.message.content =
|
||||
((baseChoice.message.content as string) ?? "") + (choice.delta.content ?? "");
|
||||
if (choice.delta?.function_call) {
|
||||
const fnCall = baseChoice.message.function_call ?? {};
|
||||
fnCall.name =
|
||||
((fnCall.name as string) ?? "") + ((choice.delta.function_call.name as string) ?? "");
|
||||
fnCall.arguments =
|
||||
((fnCall.arguments as string) ?? "") +
|
||||
((choice.delta.function_call.arguments as string) ?? "");
|
||||
}
|
||||
} else {
|
||||
// @ts-expect-error the types are correctly telling us that finish_reason
|
||||
// could be null, but don't want to fix it right now.
|
||||
choices.push({ ...omit(choice, "delta"), message: { role: "assistant", ...choice.delta } });
|
||||
}
|
||||
}
|
||||
|
||||
const merged: ChatCompletion = {
|
||||
...base,
|
||||
choices,
|
||||
};
|
||||
|
||||
return merged;
|
||||
}
|
||||
26
client-libs/typescript/src/shared.ts
Normal file
26
client-libs/typescript/src/shared.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import pkg from "../package.json";
|
||||
|
||||
export type OpenPipeConfig = {
|
||||
apiKey?: string;
|
||||
baseUrl?: string;
|
||||
};
|
||||
|
||||
export type OpenPipeArgs = {
|
||||
openpipe?: { cache?: boolean; tags?: Record<string, string> };
|
||||
};
|
||||
|
||||
export type OpenPipeMeta = {
|
||||
cacheStatus: "HIT" | "MISS" | "SKIP";
|
||||
|
||||
// We report your call to OpenPipe asynchronously in the background. If you
|
||||
// need to wait until the report is sent to take further action, you can await
|
||||
// this promise.
|
||||
reportingFinished: Promise<void | { status: "ok" }>;
|
||||
};
|
||||
|
||||
export const getTags = (args: OpenPipeArgs["openpipe"]): Record<string, string> => ({
|
||||
...args?.tags,
|
||||
...(args?.cache ? { $cache: args.cache?.toString() } : {}),
|
||||
$sdk: "typescript",
|
||||
"$sdk.version": pkg.version,
|
||||
});
|
||||
@@ -15,10 +15,7 @@
|
||||
"incremental": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
|
||||
Reference in New Issue
Block a user