From a7647b893e1f2643751882d1d668d504eea6239c Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Sat, 3 Aug 2024 22:54:04 -0500 Subject: [PATCH] feat: add EchoAITool and turbo build pipeline --- .gitignore | 4 +- examples/ai-sdk/package.json | 1 - package.json | 27 +++-------- packages/ai-sdk/package.json | 1 - packages/ai-sdk/src/ai-sdk.test.ts | 10 ++++ packages/calculator/src/calculator.ts | 3 +- packages/core/package.json | 4 +- packages/core/src/_utils.ts | 2 - packages/core/src/ai-function-set.test.ts | 44 +++++++++-------- packages/core/src/echo.ts | 30 ++++++++++++ packages/core/src/index.ts | 1 + packages/weather/package.json | 1 - pnpm-lock.yaml | 29 +++++++---- turbo.json | 59 ++++++++--------------- 14 files changed, 121 insertions(+), 95 deletions(-) create mode 100644 packages/ai-sdk/src/ai-sdk.test.ts create mode 100644 packages/core/src/echo.ts diff --git a/.gitignore b/.gitignore index b9ce49513..37ea1adba 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ node_modules # next.js .next/ -out/ # production build/ @@ -29,6 +28,9 @@ yarn-error.log* # local env files .env*.local +# turbo +.turbo + # vercel .vercel diff --git a/examples/ai-sdk/package.json b/examples/ai-sdk/package.json index 2fb792470..f75f40121 100644 --- a/examples/ai-sdk/package.json +++ b/examples/ai-sdk/package.json @@ -14,7 +14,6 @@ "build": "tsc", "clean": "del dist", "test": "run-s test:*", - "test:format": "prettier --check \"**/*.{js,ts,tsx}\"", "test:lint": "eslint .", "test:typecheck": "tsc --noEmit" }, diff --git a/package.json b/package.json index d686236c2..daca99a7b 100644 --- a/package.json +++ b/package.json @@ -13,27 +13,16 @@ }, "type": "module", "scripts": { - "build": "run-s build:*", - "build:core": "cd packages/core && pnpm build", - "build:ai-sdk": "cd packages/ai-sdk && pnpm build", - "build:weather": "cd packages/weather && pnpm build", - "build:examples": "cd examples/ai-sdk && pnpm build", - "clean": "run-s clean:*", - "clean:core": "cd packages/core && pnpm clean", - "clean:ai-sdk": "cd packages/ai-sdk && pnpm clean", - "clean:weather": "cd packages/weather && pnpm clean", - "clean:examples": "cd examples/ai-sdk && pnpm clean", - "prebuild": "run-s clean", + "build": "turbo build", + "clean": "turbo clean", + "test": "turbo test", + "test:format": "prettier --check \"**/*.{js,ts,tsx}\"", + "test:lint": "turbo test:lint", + "test:typecheck": "turbo test:typecheck", + "test:unit": "turbo test:unit", "precommit": "lint-staged", - "predev": "run-s clean", "preinstall": "npx only-allow pnpm", - "pretest": "run-s build", - "prepare": "husky", - "test": "run-s test:*", - "test:format": "prettier --check \"**/*.{js,ts,tsx}\"", - "test:lint": "eslint .", - "test:typecheck": "tsc --noEmit", - "test:unit": "vitest run" + "prepare": "husky" }, "devDependencies": { "@fisch0920/eslint-config": "^1.4.0", diff --git a/packages/ai-sdk/package.json b/packages/ai-sdk/package.json index 8ce9e8965..b63cd7076 100644 --- a/packages/ai-sdk/package.json +++ b/packages/ai-sdk/package.json @@ -27,7 +27,6 @@ "dev": "tsup --watch", "clean": "del dist", "test": "run-s test:*", - "test:format": "prettier --check \"**/*.{js,ts,tsx}\"", "test:lint": "eslint .", "test:typecheck": "tsc --noEmit", "test:unit": "vitest run" diff --git a/packages/ai-sdk/src/ai-sdk.test.ts b/packages/ai-sdk/src/ai-sdk.test.ts new file mode 100644 index 000000000..a67cfa23f --- /dev/null +++ b/packages/ai-sdk/src/ai-sdk.test.ts @@ -0,0 +1,10 @@ +import { EchoAITool } from '@agentic/core' +import { describe, expect, test } from 'vitest' + +import { createAISDKTools } from './ai-sdk' + +describe('ai-sdk', () => { + test('createAISDKTools', () => { + expect(createAISDKTools(new EchoAITool())).toHaveProperty('echo') + }) +}) diff --git a/packages/calculator/src/calculator.ts b/packages/calculator/src/calculator.ts index f39cc1d97..8b2fcf5fe 100644 --- a/packages/calculator/src/calculator.ts +++ b/packages/calculator/src/calculator.ts @@ -1,8 +1,7 @@ +import { createAIFunction } from '@agentic/core' import { evaluate } from 'mathjs' import { z } from 'zod' -import { createAIFunction } from '../create-ai-function' - // TODO: ensure `expr` is sanitized to not run arbitrary code export const CalculatorInputSchema = z.object({ diff --git a/packages/core/package.json b/packages/core/package.json index d267bdf8f..31f212c06 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,7 +27,6 @@ "dev": "tsup --watch", "clean": "del dist", "test": "run-s test:*", - "test:format": "prettier --check \"**/*.{js,ts,tsx}\"", "test:lint": "eslint .", "test:typecheck": "tsc --noEmit", "test:unit": "vitest run" @@ -52,7 +51,8 @@ "zod": "^3.23.3" }, "devDependencies": { - "@agentic/tsconfig": "workspace:*" + "@agentic/tsconfig": "workspace:*", + "openai-fetch": "^2.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/core/src/_utils.ts b/packages/core/src/_utils.ts index 81c492626..43d2605a4 100644 --- a/packages/core/src/_utils.ts +++ b/packages/core/src/_utils.ts @@ -1,5 +1,3 @@ -import 'dotenv/config' - import defaultKy, { type AfterResponseHook, type BeforeRequestHook, diff --git a/packages/core/src/ai-function-set.test.ts b/packages/core/src/ai-function-set.test.ts index 39dee18db..e23b4799a 100644 --- a/packages/core/src/ai-function-set.test.ts +++ b/packages/core/src/ai-function-set.test.ts @@ -2,32 +2,38 @@ import { expect, test } from 'vitest' import { z } from 'zod' import { AIFunctionSet } from './ai-function-set' -import { aiFunction, AIFunctionsProvider } from './fns' -import { calculator } from './tools/calculator' - -class MockAITool extends AIFunctionsProvider { - @aiFunction({ - name: 'echo', - description: 'Echoes the input.', - inputSchema: z.object({ - query: z.string().describe('input query to echo') - }) - }) - async echo({ query }: { query: string }) { - return query +import { createAIFunction } from './create-ai-function' +import { EchoAITool } from './echo' + +export const CalculatorInputSchema = z.object({ + expr: z.string().describe('mathematical expression to evaluate') +}) +export type CalculatorInput = z.infer + +const mockCalculator = createAIFunction( + { + name: 'calculator', + description: + 'Computes the result of simple mathematical expressions. Handles basic arithmetic operations like addition, subtraction, multiplication, and division. Example expressions: "1 + 2", "3.4 * 5 / 9", "4 - 2"', + inputSchema: CalculatorInputSchema + }, + async (input: CalculatorInput) => { + // eslint-disable-next-line no-eval, security/detect-eval-with-expression + const result: number = eval(input.expr) + return result } -} +) test('AIFunctionSet constructor', () => { - const mockAITool = new MockAITool() - const s0 = new AIFunctionSet([mockAITool, calculator]) + const mockAITool = new EchoAITool() + const s0 = new AIFunctionSet([mockAITool, mockCalculator]) expect(s0.size).toEqual(2) expect(s0.get('echo')).toBeDefined() expect(s0.get('calculator')).toBeDefined() expect([...s0].length).toEqual(2) - const s1 = new AIFunctionSet([s0, mockAITool, calculator, calculator]) + const s1 = new AIFunctionSet([s0, mockAITool, mockCalculator, mockCalculator]) expect(s0.size).toEqual(2) expect(s1.size).toEqual(2) expect(s1.get('echo')).toBeDefined() @@ -36,9 +42,9 @@ test('AIFunctionSet constructor', () => { }) test('AIFunctionSet constructor invalid function', () => { - const mockAITool = new MockAITool() + const mockAITool = new EchoAITool() expect( - () => new AIFunctionSet([mockAITool, calculator, { spec: {} } as any]) + () => new AIFunctionSet([mockAITool, mockCalculator, { spec: {} } as any]) ).toThrowError('Invalid AIFunctionLike: [object Object]') }) diff --git a/packages/core/src/echo.ts b/packages/core/src/echo.ts new file mode 100644 index 000000000..9ad48320e --- /dev/null +++ b/packages/core/src/echo.ts @@ -0,0 +1,30 @@ +import { z } from 'zod' + +import { createAIFunction } from './create-ai-function' +import { aiFunction, AIFunctionsProvider } from './fns' + +export class EchoAITool extends AIFunctionsProvider { + @aiFunction({ + name: 'echo', + description: 'Echoes the input.', + inputSchema: z.object({ + query: z.string().describe('input query to echo') + }) + }) + async echo({ query }: { query: string }) { + return query + } +} + +export const echoAIFunction = createAIFunction( + { + name: 'echo', + description: 'Echoes the input.', + inputSchema: z.object({ + query: z.string().describe('input query to echo') + }) + }, + ({ query }: { query: string }) => { + return query + } +) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 3881b5833..9f37575af 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,6 +1,7 @@ export * from './ai-function-set' export * from './create-ai-chain' export * from './create-ai-function' +export * from './echo' export * from './errors' export * from './extract-object' export * from './fns' diff --git a/packages/weather/package.json b/packages/weather/package.json index a9b113fe4..918602f13 100644 --- a/packages/weather/package.json +++ b/packages/weather/package.json @@ -27,7 +27,6 @@ "dev": "tsup --watch", "clean": "del dist", "test": "run-s test:*", - "test:format": "prettier --check \"**/*.{js,ts,tsx}\"", "test:lint": "eslint .", "test:typecheck": "tsc --noEmit" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0c8ca3152..0ebdead74 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -158,6 +158,9 @@ importers: '@agentic/tsconfig': specifier: workspace:* version: link:../tsconfig + openai-fetch: + specifier: ^2.0.4 + version: 2.0.4 packages/tsconfig: {} @@ -2900,6 +2903,10 @@ packages: resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} engines: {node: '>=18'} + openai-fetch@2.0.4: + resolution: {integrity: sha512-+1sC+mYpGi79YXaJsySxTtYeWkDULS/fhRCr8PLI+xcpnqFfoFY/VL0f4avQAnJSf1LZRaTrrKOK8yqxrYI5BQ==} + engines: {node: '>=18'} + openai@4.54.0: resolution: {integrity: sha512-e/12BdtTtj+tXs7iHm+Dm7H7WjEWnw7O52B2wSfCQ6lD5F6cvjzo7cANXy5TJ1Q3/qc8YRPT5wBTTFtP5sBp1g==} hasBin: true @@ -4393,8 +4400,8 @@ snapshots: '@typescript-eslint/parser': 7.17.0(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/utils': 7.17.0(eslint@8.57.0)(typescript@5.5.4) eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jest: 28.6.0(@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) eslint-plugin-jest-dom: 5.4.0(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0) @@ -5629,13 +5636,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: debug: 4.3.6 enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.6 is-core-module: 2.15.0 @@ -5646,18 +5653,18 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.17.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -5667,7 +5674,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.0 is-glob: 4.0.3 @@ -7006,6 +7013,10 @@ snapshots: is-inside-container: 1.0.0 is-wsl: 3.1.0 + openai-fetch@2.0.4: + dependencies: + ky: 1.5.0 + openai@4.54.0: dependencies: '@types/node': 18.19.43 diff --git a/turbo.json b/turbo.json index b7f783844..335421c26 100644 --- a/turbo.json +++ b/turbo.json @@ -1,54 +1,37 @@ { "$schema": "https://turbo.build/schema.json", - "pipeline": { + "ui": "stream", + "tasks": { "build": { "dependsOn": ["^build"], - "env": [ - "ANTHROPIC_API_KEY", - "AWS_REGION", - "AWS_ACCESS_KEY_ID", - "AWS_SECRET_ACCESS_KEY", - "COHERE_API_KEY", - "FIREWORKS_API_KEY", - "GOOGLE_API_KEY", - "GROQ_API_KEY", - "HUGGINGFACE_API_KEY", - "MISTRAL_API_KEY", - "OPENAI_API_KEY", - "OPENAI_API_BASE", - "PERPLEXITY_API_KEY", - "REPLICATE_API_KEY", - "NODE_ENV", - "ASSISTANT_ID", - "INKEEP_API_KEY", - "INKEEP_INTEGRATION_ID", - "VERCEL_URL" - ], "outputs": ["dist/**"] }, - "lint": { - "dependsOn": ["^lint"] - }, - "type-check": { - "dependsOn": ["^build", "build"] + "clean": { + "dependsOn": ["^clean"], + "outputs": ["dist/**"] }, "test": { - "dependsOn": ["^build", "build"] + "dependsOn": [ + "build", + "test:format", + "test:lint", + "test:typecheck", + "test:unit" + ] }, - "publint": { - "dependsOn": ["^build", "build"] + "test:lint": { + "dependsOn": ["^test:lint"] }, - "clean": { - "dependsOn": ["^clean"] + "test:typecheck": { + "dependsOn": ["^test:typecheck"] + }, + "test:unit": { + "dependsOn": ["^test:unit"] }, + "test:format": {}, "dev": { "cache": false, "persistent": true - }, - "prettier-check": {}, - "integration-test": { - "dependsOn": ["^build", "build"] } - }, - "globalEnv": ["CI", "PORT"] + } }