kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/643/head^2
rodzic
839f46097c
commit
8aa53fed71
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"extends": ["@fisch0920/eslint-config", "@fisch0920/eslint-config/node"]
|
"extends": ["@fisch0920/eslint-config/node"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
import 'dotenv/config'
|
||||||
|
|
||||||
|
import { openai } from '@ai-sdk/openai'
|
||||||
|
import { generateText } from 'ai'
|
||||||
|
|
||||||
|
import { WeatherClient } from '../../src/index.js'
|
||||||
|
import { tools } from '../../src/sdks/ai-sdk.js'
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const weather = new WeatherClient()
|
||||||
|
|
||||||
|
const result = await generateText({
|
||||||
|
model: openai('gpt-4-turbo'),
|
||||||
|
tools: tools(weather),
|
||||||
|
toolChoice: 'required',
|
||||||
|
prompt:
|
||||||
|
'What is the weather in San Francisco and what attractions should I visit?'
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(result.toolResults[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
await main()
|
|
@ -7,11 +7,10 @@ import {
|
||||||
createAIRunner,
|
createAIRunner,
|
||||||
Msg
|
Msg
|
||||||
} from '@dexaai/dexter'
|
} from '@dexaai/dexter'
|
||||||
import { gracefulExit } from 'exit-hook'
|
|
||||||
import restoreCursor from 'restore-cursor'
|
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
|
|
||||||
import { WeatherClient } from '../src/index.js'
|
import { WeatherClient } from '../../src/index.js'
|
||||||
|
import { functions } from '../../src/sdks/dexter.js'
|
||||||
|
|
||||||
/** Get the capital city for a given state. */
|
/** Get the capital city for a given state. */
|
||||||
const getCapitalCity = createAIFunction(
|
const getCapitalCity = createAIFunction(
|
||||||
|
@ -46,31 +45,14 @@ const getCapitalCity = createAIFunction(
|
||||||
|
|
||||||
const weather = new WeatherClient()
|
const weather = new WeatherClient()
|
||||||
|
|
||||||
const fns = [...weather.functions]
|
|
||||||
console.log('fns', fns)
|
|
||||||
|
|
||||||
const getCurrentWeather = weather.functions.get('get_current_weather')!
|
|
||||||
console.log('get_current_weather', getCurrentWeather)
|
|
||||||
|
|
||||||
/** A runner that uses the weather and capital city functions. */
|
/** A runner that uses the weather and capital city functions. */
|
||||||
const weatherCapitalRunner = createAIRunner({
|
const weatherCapitalRunner = createAIRunner({
|
||||||
chatModel: new ChatModel({ params: { model: 'gpt-4-1106-preview' } }),
|
chatModel: new ChatModel({ params: { model: 'gpt-4-1106-preview' } }),
|
||||||
functions: [
|
functions: [...functions(weather), getCapitalCity],
|
||||||
createAIFunction(
|
|
||||||
{
|
|
||||||
...getCurrentWeather.spec,
|
|
||||||
argsSchema: getCurrentWeather.inputSchema
|
|
||||||
},
|
|
||||||
getCurrentWeather.impl
|
|
||||||
),
|
|
||||||
getCapitalCity
|
|
||||||
],
|
|
||||||
systemMessage: `You use functions to answer questions about the weather and capital cities.`
|
systemMessage: `You use functions to answer questions about the weather and capital cities.`
|
||||||
})
|
})
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
restoreCursor()
|
|
||||||
|
|
||||||
// Run with a string input
|
// Run with a string input
|
||||||
const rString = await weatherCapitalRunner(
|
const rString = await weatherCapitalRunner(
|
||||||
`Whats the capital of California and NY and the weather for both?`
|
`Whats the capital of California and NY and the weather for both?`
|
||||||
|
@ -88,9 +70,4 @@ async function main() {
|
||||||
console.log('rMessage', rMessage)
|
console.log('rMessage', rMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
await main()
|
||||||
await main()
|
|
||||||
} catch (err) {
|
|
||||||
console.error('unexpected error', err)
|
|
||||||
gracefulExit(1)
|
|
||||||
}
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"name": "agentic-examples",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "TODO",
|
||||||
|
"author": "Travis Fischer <travis@transitivebullsh.it>",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "transitive-bullshit/agentic"
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@9.1.4",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"preinstall": "npx only-allow pnpm",
|
||||||
|
"build": "tsc",
|
||||||
|
"clean": "del dist",
|
||||||
|
"prebuild": "run-s clean",
|
||||||
|
"pretest": "run-s build",
|
||||||
|
"test": "run-s test:*",
|
||||||
|
"test:typecheck": "tsc --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ai": "^3.1.22",
|
||||||
|
"@ai-sdk/openai": "^0.0.18",
|
||||||
|
"@dexaai/dexter": "^2.0.3",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"zod": "^3.23.3"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"include": ["ai-sdk", "dexter"]
|
||||||
|
}
|
27
package.json
27
package.json
|
@ -1,28 +1,32 @@
|
||||||
{
|
{
|
||||||
"name": "gptlint",
|
"name": "@agentic/stdlib",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "TODO",
|
"description": "TODO",
|
||||||
"author": "Travis Fischer <travis@transitivebullsh.it>",
|
"author": "Travis Fischer <travis@transitivebullsh.it>",
|
||||||
"license": "PROPRIETARY",
|
"license": "MIT",
|
||||||
"homepage": "https://trywalter.ai",
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "transitive-bullshit/walter"
|
"url": "transitive-bullshit/agentic"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@8.15.7",
|
"packageManager": "pnpm@9.1.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"source": "./src/gptlint.ts",
|
"source": "./src/index.ts",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/src/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"import": "./dist/src/index.js",
|
"import": "./dist/index.js",
|
||||||
"default": "./dist/src/index.js"
|
"default": "./dist/index.js"
|
||||||
|
},
|
||||||
|
"./ai-sdk": {
|
||||||
|
"types": "./dist/sdks/ai-sdk.d.ts",
|
||||||
|
"import": "./dist/sdks/ai-sdk.js",
|
||||||
|
"default": "./dist/sdks/ai-sdk.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
@ -67,6 +71,7 @@
|
||||||
"@fisch0920/eslint-config": "^1.3.1",
|
"@fisch0920/eslint-config": "^1.3.1",
|
||||||
"@total-typescript/ts-reset": "^0.5.1",
|
"@total-typescript/ts-reset": "^0.5.1",
|
||||||
"@types/node": "^20.12.7",
|
"@types/node": "^20.12.7",
|
||||||
|
"ai": "^3.1.22",
|
||||||
"del-cli": "^5.1.0",
|
"del-cli": "^5.1.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"husky": "^9.0.11",
|
"husky": "^9.0.11",
|
||||||
|
@ -81,6 +86,10 @@
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"vitest": "2.0.0-beta.3"
|
"vitest": "2.0.0-beta.3"
|
||||||
},
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@dexaai/dexter": "^2.0.3",
|
||||||
|
"ai": "^3.1.22"
|
||||||
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{ts,tsx}": [
|
"*.{ts,tsx}": [
|
||||||
"eslint --fix",
|
"eslint --fix",
|
||||||
|
|
1022
pnpm-lock.yaml
1022
pnpm-lock.yaml
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,2 @@
|
||||||
|
packages:
|
||||||
|
- 'examples'
|
11380
proxycurl-openapi.json
11380
proxycurl-openapi.json
File diff suppressed because one or more lines are too long
Plik diff jest za duży
Load Diff
|
@ -15,7 +15,7 @@ export class AIFunctionSet implements Iterable<types.AIFunction> {
|
||||||
}
|
}
|
||||||
|
|
||||||
add(fn: types.AIFunction): this {
|
add(fn: types.AIFunction): this {
|
||||||
this._map.set(fn.name, fn)
|
this._map.set(fn.spec.name, fn)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,10 @@ export class AIFunctionSet implements Iterable<types.AIFunction> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map<T>(fn: (fn: types.AIFunction) => T): T[] {
|
||||||
|
return [...this.entries].map(fn)
|
||||||
|
}
|
||||||
|
|
||||||
get entries(): IterableIterator<types.AIFunction> {
|
get entries(): IterableIterator<types.AIFunction> {
|
||||||
return this._map.values()
|
return this._map.values()
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,10 @@ export class AIToolSet implements Iterable<types.AITool> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map<T>(fn: (fn: types.AITool) => T): T[] {
|
||||||
|
return [...this.entries].map(fn)
|
||||||
|
}
|
||||||
|
|
||||||
get entries(): IterableIterator<types.AITool> {
|
get entries(): IterableIterator<types.AITool> {
|
||||||
return this._map.values()
|
return this._map.values()
|
||||||
}
|
}
|
||||||
|
|
26
src/fns.ts
26
src/fns.ts
|
@ -8,6 +8,13 @@ import { AIFunctionSet } from './ai-function-set.js'
|
||||||
import { AIToolSet } from './ai-tool-set.js'
|
import { AIToolSet } from './ai-tool-set.js'
|
||||||
import { assert } from './utils.js'
|
import { assert } from './utils.js'
|
||||||
|
|
||||||
|
export interface Invocable {
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
inputSchema: z.AnyZodObject
|
||||||
|
methodName: string
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class AIToolsProvider {
|
export abstract class AIToolsProvider {
|
||||||
private _tools?: AIToolSet
|
private _tools?: AIToolSet
|
||||||
private _functions?: AIFunctionSet
|
private _functions?: AIFunctionSet
|
||||||
|
@ -25,7 +32,7 @@ export abstract class AIToolsProvider {
|
||||||
const metadata = this.constructor[Symbol.metadata]
|
const metadata = this.constructor[Symbol.metadata]
|
||||||
assert(metadata)
|
assert(metadata)
|
||||||
const invocables = (metadata?.invocables as Invocable[]) ?? []
|
const invocables = (metadata?.invocables as Invocable[]) ?? []
|
||||||
console.log({ metadata, invocables })
|
// console.log({ metadata, invocables })
|
||||||
|
|
||||||
const aiFunctions = invocables.map((invocable) => {
|
const aiFunctions = invocables.map((invocable) => {
|
||||||
const impl = (this as any)[invocable.methodName]?.bind(this)
|
const impl = (this as any)[invocable.methodName]?.bind(this)
|
||||||
|
@ -41,13 +48,6 @@ export abstract class AIToolsProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Invocable {
|
|
||||||
name: string
|
|
||||||
description?: string
|
|
||||||
inputSchema: z.AnyZodObject
|
|
||||||
methodName: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function aiFunction<
|
export function aiFunction<
|
||||||
This,
|
This,
|
||||||
InputSchema extends z.SomeZodObject,
|
InputSchema extends z.SomeZodObject,
|
||||||
|
@ -87,11 +87,11 @@ export function aiFunction<
|
||||||
inputSchema,
|
inputSchema,
|
||||||
methodName
|
methodName
|
||||||
})
|
})
|
||||||
console.log({
|
// console.log({
|
||||||
name,
|
// name,
|
||||||
methodName,
|
// methodName,
|
||||||
context
|
// context
|
||||||
})
|
// })
|
||||||
|
|
||||||
// context.addInitializer(function () {
|
// context.addInitializer(function () {
|
||||||
// ;(this as any)[methodName] = (this as any)[methodName].bind(this)
|
// ;(this as any)[methodName] = (this as any)[methodName].bind(this)
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { tool } from 'ai'
|
||||||
|
|
||||||
|
import type { AIFunctionSet } from '../ai-function-set.js'
|
||||||
|
import { AIToolsProvider } from '../fns.js'
|
||||||
|
|
||||||
|
export function tools(tools: AIToolsProvider | AIFunctionSet) {
|
||||||
|
const fns = tools instanceof AIToolsProvider ? tools.functions : tools
|
||||||
|
|
||||||
|
return Object.fromEntries(
|
||||||
|
[...fns].map((fn) => [
|
||||||
|
fn.spec.name,
|
||||||
|
tool({
|
||||||
|
description: fn.spec.description,
|
||||||
|
parameters: fn.inputSchema,
|
||||||
|
execute: fn.impl
|
||||||
|
})
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { createAIFunction } from '@dexaai/dexter'
|
||||||
|
|
||||||
|
import type { AIFunctionSet } from '../ai-function-set.js'
|
||||||
|
import { AIToolsProvider } from '../fns.js'
|
||||||
|
|
||||||
|
export function functions(input: AIToolsProvider | AIFunctionSet) {
|
||||||
|
const fns = input instanceof AIToolsProvider ? input.functions : input
|
||||||
|
|
||||||
|
return fns.map((fn) =>
|
||||||
|
createAIFunction(
|
||||||
|
{
|
||||||
|
name: fn.spec.name,
|
||||||
|
description: fn.spec.description,
|
||||||
|
argsSchema: fn.inputSchema
|
||||||
|
},
|
||||||
|
fn.impl
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import defaultKy, { type KyInstance } from 'ky'
|
import defaultKy, { type KyInstance } from 'ky'
|
||||||
import * as z from 'zod'
|
import { z } from 'zod'
|
||||||
|
|
||||||
import { assert, getEnv } from '../utils.js'
|
import { assert, getEnv } from '../utils.js'
|
||||||
|
|
||||||
|
|
|
@ -126,18 +126,4 @@ export class WeatherClient extends AIToolsProvider {
|
||||||
})
|
})
|
||||||
.json<weatherapi.CurrentWeatherResponse>()
|
.json<weatherapi.CurrentWeatherResponse>()
|
||||||
}
|
}
|
||||||
|
|
||||||
async ipInfo(ipOrOptions: string | { q: string }) {
|
|
||||||
const options =
|
|
||||||
typeof ipOrOptions === 'string' ? { q: ipOrOptions } : ipOrOptions
|
|
||||||
|
|
||||||
return this.ky
|
|
||||||
.get('ip.json', {
|
|
||||||
searchParams: {
|
|
||||||
key: this.apiKey,
|
|
||||||
...options
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.json<weatherapi.WeatherIPInfoResponse>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
12
src/types.ts
12
src/types.ts
|
@ -22,16 +22,19 @@ export interface AIToolSpec {
|
||||||
function: AIFunctionSpec
|
function: AIFunctionSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The implementation of the function, with arg parsing and validation. */
|
||||||
|
export type AIFunctionImpl<Return> = Omit<
|
||||||
|
(input: string | Msg) => MaybePromise<Return>,
|
||||||
|
'name' | 'toString' | 'arguments' | 'caller' | 'prototype' | 'length'
|
||||||
|
>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function meant to be used with LLM function calling.
|
* A function meant to be used with LLM function calling.
|
||||||
*/
|
*/
|
||||||
export interface AIFunction<
|
export interface AIFunction<
|
||||||
InputSchema extends z.ZodObject<any> = z.ZodObject<any>,
|
InputSchema extends z.ZodObject<any> = z.ZodObject<any>,
|
||||||
Return = any
|
Return = any
|
||||||
> {
|
> extends AIFunctionImpl<Return> {
|
||||||
/** The implementation of the function, with arg parsing and validation. */
|
|
||||||
(input: string | Msg): MaybePromise<Return>
|
|
||||||
|
|
||||||
/** The Zod schema for the arguments string. */
|
/** The Zod schema for the arguments string. */
|
||||||
inputSchema: InputSchema
|
inputSchema: InputSchema
|
||||||
|
|
||||||
|
@ -41,6 +44,7 @@ export interface AIFunction<
|
||||||
/** The function spec for the OpenAI API `functions` property. */
|
/** The function spec for the OpenAI API `functions` property. */
|
||||||
spec: AIFunctionSpec
|
spec: AIFunctionSpec
|
||||||
|
|
||||||
|
/** The underlying function implementation without any arg parsing or validation. */
|
||||||
impl: (params: z.infer<InputSchema>) => MaybePromise<Return>
|
impl: (params: z.infer<InputSchema>) => MaybePromise<Return>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,5 +25,5 @@
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"sourceMap": true
|
"sourceMap": true
|
||||||
},
|
},
|
||||||
"include": ["src", "bin"]
|
"include": ["src"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { defineConfig } from 'tsup'
|
||||||
|
|
||||||
export default defineConfig([
|
export default defineConfig([
|
||||||
{
|
{
|
||||||
entry: ['src/index.ts'],
|
entry: ['src/index.ts', 'src/sdks/ai-sdk.ts'],
|
||||||
outDir: 'dist',
|
outDir: 'dist',
|
||||||
target: 'node18',
|
target: 'node18',
|
||||||
platform: 'node',
|
platform: 'node',
|
||||||
|
|
Ładowanie…
Reference in New Issue