From 2e92b819b2cfbf096241992d981cd66f0125d6b6 Mon Sep 17 00:00:00 2001 From: Joe McIlvain Date: Fri, 3 May 2024 12:26:27 -0700 Subject: [PATCH] chore: Add CI with GitHub Actions. Also, files have been reformatted so that the formatting check in CI will pass. --- .github/workflows/ci.yaml | 30 ++++++++++ package.json | 62 +++++++++++---------- pnpm-lock.yaml | 10 ++++ spec/KurtOpenAI.spec.ts | 6 +- spec/KurtResult.spec.ts | 10 ++-- spec/KurtVertexAI.spec.ts | 12 ++-- src/Kurt.ts | 4 +- src/KurtOpenAI.ts | 10 ++-- src/KurtResult.ts | 2 +- src/KurtVertexAI.ts | 14 ++--- src/VertexAI.patch.generateContentStream.ts | 12 ++-- tsconfig.json | 2 +- 12 files changed, 109 insertions(+), 65 deletions(-) create mode 100644 .github/workflows/ci.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..8c29aee --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,30 @@ +name: ci + +on: + workflow_dispatch: # allow manual trigger + pull_request: # on pull request changes + push: + branches: [main] # on commits to the main branch + +jobs: + ci: + runs-on: ubuntu-latest + permissions: + contents: write # to publish releases + issues: write # to comment on released issues + pull-requests: write # to comment on released PRs + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v2.5.1 + with: { node-version: 20.x } + - run: npm install -g pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm run -r format:check + - run: pnpm run -r test + - run: pnpm run -r build + # - run: pnpm run -r release + # env: + # GITHUB_TOKEN: ${{ github.token }} + # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/package.json b/package.json index 85f545e..8be6f8f 100644 --- a/package.json +++ b/package.json @@ -1,31 +1,35 @@ { - "name": "@formula-monks/kurt", - "description": "A wrapper for AI SDKs, for building LLM-agnostic structured AI applications", - "license": "MIT", - "version": "1.0.0", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "files": [ - "dist" - ], - "scripts": { - "test": "jest", - "prepack": "tsc" - }, - "prettier": { - "semi": false - }, - "dependencies": { - "@google-cloud/vertexai": "1.1.0", - "openai": "^4.40.0", - "zod": "^3.23.5", - "zod-to-json-schema": "^3.23.0" - }, - "devDependencies": { - "@jest/globals": "^29.7.0", - "jest": "^29.7.0", - "ts-jest": "^29.1.2", - "type-fest": "^4.18.1", - "typescript": "^5.4.5" - } + "name": "@formula-monks/kurt", + "description": "A wrapper for AI SDKs, for building LLM-agnostic structured AI applications", + "license": "MIT", + "version": "1.0.0", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "test": "jest", + "format": "prettier --write ./**/*.{ts,js,json,md}", + "format:check": "prettier --check ./**/*.{ts,js,json,md}", + "build": "tsc", + "prepack": "pnpm run build" + }, + "prettier": { + "semi": false + }, + "dependencies": { + "@google-cloud/vertexai": "1.1.0", + "openai": "^4.40.0", + "zod": "^3.23.5", + "zod-to-json-schema": "^3.23.0" + }, + "devDependencies": { + "@jest/globals": "^29.7.0", + "jest": "^29.7.0", + "prettier": "^3.2.5", + "ts-jest": "^29.1.2", + "type-fest": "^4.18.1", + "typescript": "^5.4.5" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ced0dde..af9b692 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,6 +27,9 @@ importers: jest: specifier: ^29.7.0 version: 29.7.0(@types/node@18.19.31) + prettier: + specifier: ^3.2.5 + version: 3.2.5 ts-jest: specifier: ^29.1.2 version: 29.1.2(@babel/core@7.24.5)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.5))(jest@29.7.0(@types/node@18.19.31))(typescript@5.4.5) @@ -1097,6 +1100,11 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2737,6 +2745,8 @@ snapshots: dependencies: find-up: 4.1.0 + prettier@3.2.5: {} + pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 diff --git a/spec/KurtOpenAI.spec.ts b/spec/KurtOpenAI.spec.ts index 1d403b3..5dd8bc8 100644 --- a/spec/KurtOpenAI.spec.ts +++ b/spec/KurtOpenAI.spec.ts @@ -14,7 +14,7 @@ const USE_REAL_API = false // set to true to validate against actual OpenAI function setupExpectingCall( expectedRequest: OpenAIRequest, - responseChunks: OpenAIResponseChunk["choices"][number][] + responseChunks: OpenAIResponseChunk["choices"][number][], ) { const openAI: OpenAI = USE_REAL_API ? new RealOpenAI() @@ -68,7 +68,7 @@ describe("KurtOpenAI", () => { { delta: { content: " today" }, finish_reason: null }, { delta: { content: "?" }, finish_reason: null }, { delta: { content: "" }, finish_reason: "stop" }, - ] + ], ) expect(await arrayFromAsync(kurt.generateNaturalLanguage(req))).toEqual([ @@ -170,7 +170,7 @@ describe("KurtOpenAI", () => { finish_reason: null, }, { delta: {}, finish_reason: "stop" }, - ] + ], ) expect(await arrayFromAsync(kurt.generateStructuredData(req))).toEqual([ diff --git a/spec/KurtResult.spec.ts b/spec/KurtResult.spec.ts index 858ef53..66b0169 100644 --- a/spec/KurtResult.spec.ts +++ b/spec/KurtResult.spec.ts @@ -25,7 +25,7 @@ function kurtSayHelloFinalEvent() { function kurtResultSayHello( opts: { errorBeforeFinish?: boolean - } = {} + } = {}, ) { const schema = z.object({ say: z.string() }) return new KurtResult<(typeof schema)["shape"]>( @@ -42,7 +42,7 @@ function kurtResultSayHello( // Send the event. yield event as KurtResultEvent<(typeof schema)["shape"]> } - })() + })(), ) } @@ -207,8 +207,8 @@ describe("KurtResult", () => { awaits.push( (async () => expect(await result.finalEvent).toEqual( - kurtSayHelloFinalEvent() - ))() + kurtSayHelloFinalEvent(), + ))(), ) } } @@ -244,7 +244,7 @@ describe("KurtResult", () => { listeners.push(listener) errorers.push(expectThrow("Whoops!", async () => await listener)) errorers.push( - expectThrow("Whoops!", async () => await result.finalEvent) + expectThrow("Whoops!", async () => await result.finalEvent), ) } } diff --git a/spec/KurtVertexAI.spec.ts b/spec/KurtVertexAI.spec.ts index eede050..ab502d1 100644 --- a/spec/KurtVertexAI.spec.ts +++ b/spec/KurtVertexAI.spec.ts @@ -16,7 +16,7 @@ const USE_REAL_API = false // set to true to validate against actual VertexAI function setupExpectingCall( expectedRequest: VertexAIRequest, - responseChunks: VertexAIResponseChunkCandidate[] + responseChunks: VertexAIResponseChunkCandidate[], ) { function requiredEnvVar(name: string) { const value = process.env[name] @@ -33,7 +33,7 @@ function setupExpectingCall( getGenerativeModel(...args: unknown[]) { return { generateContentStreamPATCHED( - req: VertexAIRequest + req: VertexAIRequest, ): VertexAIResponse { expect(req).toEqual(expectedRequest) @@ -79,7 +79,7 @@ describe("KurtVertexAI", () => { }, finishReason: "STOP" as any, // TODO: no any }, - ] + ], ) expect(await arrayFromAsync(kurt.generateNaturalLanguage(req))).toEqual([ @@ -139,7 +139,7 @@ describe("KurtVertexAI", () => { }, finishReason: "STOP" as any, // TODO: no any }, - ] + ], ) expect(await arrayFromAsync(kurt.generateStructuredData(req))).toEqual([ @@ -206,7 +206,7 @@ describe("KurtVertexAI", () => { }, finishReason: "STOP" as any, // TODO: no any }, - ] + ], ) expect(await arrayFromAsync(kurt.generateStructuredData(req))).toEqual([ @@ -273,7 +273,7 @@ describe("KurtVertexAI", () => { }, finishReason: "STOP" as any, // TODO: no any }, - ] + ], ) expect(await arrayFromAsync(kurt.generateStructuredData(req))).toEqual([ diff --git a/src/Kurt.ts b/src/Kurt.ts index 908032c..65ba619 100644 --- a/src/Kurt.ts +++ b/src/Kurt.ts @@ -3,11 +3,11 @@ import { KurtSchema, KurtSchemaInner } from "./KurtSchema" export interface Kurt { generateNaturalLanguage( - options: KurtGenerateNaturalLanguageOptions + options: KurtGenerateNaturalLanguageOptions, ): KurtResult generateStructuredData( - options: KurtGenerateStructuredDataOptions + options: KurtGenerateStructuredDataOptions, ): KurtResult } diff --git a/src/KurtOpenAI.ts b/src/KurtOpenAI.ts index 393b0e2..25eab90 100644 --- a/src/KurtOpenAI.ts +++ b/src/KurtOpenAI.ts @@ -36,7 +36,7 @@ export class KurtOpenAI implements Kurt { constructor(private options: KurtOpenAICreateOptions) {} generateNaturalLanguage( - options: KurtGenerateNaturalLanguageOptions + options: KurtGenerateNaturalLanguageOptions, ): KurtResult { const systemPrompt = options.systemPrompt ?? this.options.systemPrompt const prompt = options.prompt @@ -54,12 +54,12 @@ export class KurtOpenAI implements Kurt { { role: "user", content: prompt }, ...toOpenAIMessages(extraMessages), ], - }) + }), ) } generateStructuredData( - options: KurtGenerateStructuredDataOptions + options: KurtGenerateStructuredDataOptions, ): KurtResult { const systemPrompt = options.systemPrompt ?? this.options.systemPrompt const prompt = options.prompt @@ -92,13 +92,13 @@ export class KurtOpenAI implements Kurt { }, }, ], - }) + }), ) } private handleStream( schema: KurtSchemaMaybe, - response: OpenAIResponse + response: OpenAIResponse, ): KurtResult { async function* generator() { const stream = await response diff --git a/src/KurtResult.ts b/src/KurtResult.ts index 5d8aec0..ef394a8 100644 --- a/src/KurtResult.ts +++ b/src/KurtResult.ts @@ -12,7 +12,7 @@ export type KurtResultEvent = | KurtResultEventFinal type _AdditionalListener = ( - event: KurtResultEvent | { uncaughtError: unknown } + event: KurtResultEvent | { uncaughtError: unknown }, ) => void // This class represents the result of a call to an LLM. diff --git a/src/KurtVertexAI.ts b/src/KurtVertexAI.ts index 640a278..b2e118e 100644 --- a/src/KurtVertexAI.ts +++ b/src/KurtVertexAI.ts @@ -37,7 +37,7 @@ export class KurtVertexAI implements Kurt { constructor(private options: KurtVertexAICreateOptions) {} generateNaturalLanguage( - options: KurtGenerateNaturalLanguageOptions + options: KurtGenerateNaturalLanguageOptions, ): KurtResult { const systemPrompt = options.systemPrompt ?? this.options.systemPrompt const prompt = options.prompt @@ -57,12 +57,12 @@ export class KurtVertexAI implements Kurt { { role: "user", parts: [{ text: prompt }] }, ...toVertexAIMessages(extraMessages), ], - }) + }), ) } generateStructuredData( - options: KurtGenerateStructuredDataOptions + options: KurtGenerateStructuredDataOptions, ): KurtResult { const systemPrompt = options.systemPrompt ?? this.options.systemPrompt const prompt = options.prompt @@ -95,13 +95,13 @@ export class KurtVertexAI implements Kurt { ], }, ], - }) + }), ) } private handleStream( schema: KurtSchemaMaybe, - response: VertexAIResponse + response: VertexAIResponse, ): KurtResult { async function* generator() { const { stream } = await response @@ -152,7 +152,7 @@ function toVertexAIMessages(messages: KurtMessage[]): VertexAIMessage[] { } function jsonSchemaForVertexAI( - zodSchema: KurtSchema + zodSchema: KurtSchema, ) { // Vertex AI supports only a limited version of JSON schema, // so we need to make modifications here to make it work properly. @@ -192,7 +192,7 @@ function jsonSchemaForVertexAI( // and then add new logic here as needed to handle the new scenario. function applySchemaToFuzzyStructure( schema: KurtSchemaMaybe, - input: { name: string; args: object } | undefined + input: { name: string; args: object } | undefined, ): any { if (schema === undefined || input === undefined) return undefined diff --git a/src/VertexAI.patch.generateContentStream.ts b/src/VertexAI.patch.generateContentStream.ts index e1fa5fe..361c630 100644 --- a/src/VertexAI.patch.generateContentStream.ts +++ b/src/VertexAI.patch.generateContentStream.ts @@ -74,7 +74,7 @@ export async function generateContent( generationConfig?: GenerationConfig, safetySettings?: SafetySetting[], tools?: Tool[], - requestOptions?: RequestOptions + requestOptions?: RequestOptions, ): Promise { request = formatContentRequest(request, generationConfig, safetySettings) @@ -82,7 +82,7 @@ export async function generateContent( if (request.generationConfig) { request.generationConfig = validateGenerationConfig( - request.generationConfig + request.generationConfig, ) } @@ -129,14 +129,14 @@ export async function generateContentStream( generationConfig?: GenerationConfig, safetySettings?: SafetySetting[], tools?: Tool[], - requestOptions?: RequestOptions + requestOptions?: RequestOptions, ): Promise { request = formatContentRequest(request, generationConfig, safetySettings) validateGenerateContentRequest(request) if (request.generationConfig) { request.generationConfig = validateGenerationConfig( - request.generationConfig + request.generationConfig, ) } @@ -176,7 +176,7 @@ export async function generateContentStream( async function generateContentStreamPATCHED( this: VertexAI, - request: GenerateContentRequest + request: GenerateContentRequest, ): Promise { return generateContentStream( (this as any).location, @@ -188,6 +188,6 @@ async function generateContentStreamPATCHED( (this as any).generationConfig, (this as any).safetySettings, (this as any).tools, - (this as any).requestOptions + (this as any).requestOptions, ) } diff --git a/tsconfig.json b/tsconfig.json index 0847794..f9e305d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,4 +12,4 @@ "target": "ES2015", "esModuleInterop": true } -} \ No newline at end of file +}