pull/643/head^2
Travis Fischer 2024-05-22 03:11:36 -05:00
rodzic 0953469e8d
commit 0d96cef757
20 zmienionych plików z 35761 dodań i 187 usunięć

Wyświetl plik

@ -4,7 +4,8 @@ import 'dotenv/config'
import { gracefulExit } from 'exit-hook'
import restoreCursor from 'restore-cursor'
import type * as types from '@/types.js'
// import { ClearbitClient } from '../src/index.js'
import { ProxycurlClient } from '../src/services/proxycurl-client.js'
/**
* Scratch for quick testing.
@ -12,6 +13,19 @@ import type * as types from '@/types.js'
async function main() {
restoreCursor()
// const clearbit = new ClearbitClient()
// const res = await clearbit.companyEnrichment({
// domain: 'https://clay.com'
// })
// console.log(JSON.stringify(res, null, 2))
const proxycurl = new ProxycurlClient()
const res = await proxycurl.getLinkedInPerson({
linkedin_profile_url: 'https://linkedin.com/in/fisch2'
// personal_email: 'fisch0920@gmail.com'
})
console.log(JSON.stringify(res, null, 2))
return gracefulExit(0)
}

11603
json-schema.json 100644

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -45,10 +45,10 @@
},
"dependencies": {
"@dexaai/dexter": "^2.0.0",
"@nangohq/node": "^0.39.30",
"chalk": "^5.3.0",
"delay": "^6.0.0",
"dotenv": "^16.4.5",
"execa": "^8.0.1",
"exit-hook": "^4.0.0",
"jsonrepair": "^3.6.1",
"ky": "^1.2.4",
@ -56,10 +56,14 @@
"p-map": "^7.0.2",
"p-retry": "^6.2.0",
"p-throttle": "^6.1.0",
"proxycurl-js-linkedin-profile-scraper": "^1.0.2",
"reflect-metadata": "^0.2.2",
"restore-cursor": "^5.0.0",
"tiny-invariant": "^1.3.3",
"twitter-api-sdk": "^1.2.1",
"type-fest": "^4.16.0",
"zod": "^3.23.3"
"zod": "^3.23.3",
"zod-to-json-schema": "^3.23.0"
},
"devDependencies": {
"@fisch0920/eslint-config": "^1.3.1",
@ -68,12 +72,12 @@
"del-cli": "^5.1.0",
"eslint": "^8.57.0",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"lint-staged": "^15.2.4",
"np": "^10.0.5",
"npm-run-all2": "^6.1.2",
"npm-run-all2": "^6.2.0",
"prettier": "^3.2.5",
"tsup": "^8.0.2",
"tsx": "^4.7.2",
"tsx": "^4.10.5",
"typescript": "^5.4.5",
"vite": "^5.2.10",
"vitest": "^1.5.0"

Plik diff jest za duży Load Diff

11380
proxycurl-openapi.json 100644

File diff suppressed because one or more lines are too long

Plik diff jest za duży Load Diff

Wyświetl plik

@ -9,13 +9,6 @@ import { zodToJsonSchema } from './zod-to-json-schema.js'
export const invocableMetadataKey = Symbol('invocable')
export interface Invocable {
name: string
description?: string
inputSchema?: z.AnyZodObject
callback: (args: Record<string, any>) => Promise<any>
}
export abstract class AIToolsProvider {
private _tools?: ToolSet
private _functions?: FunctionSet
@ -34,7 +27,16 @@ export abstract class AIToolsProvider {
get functions(): FunctionSet {
if (!this._functions) {
const invocables = getInvocables(this)
const metadata = this.constructor[Symbol.metadata]
const invocables = (metadata?.invocables as Invocable[]) ?? []
const namespace = this.namespace
const functions = invocables.map((invocable) => ({
...invocable,
name: invocable.name ?? `${namespace}_${invocable.propertyKey}`,
callback: (target as any)[invocable.propertyKey].bind(target)
}))
const functions = invocables.map(getFunctionSpec)
this._functions = new FunctionSet(functions)
}
@ -43,7 +45,14 @@ export abstract class AIToolsProvider {
}
}
export function getFunctionSpec(invocable: Invocable): types.AIFunctionSpec {
export interface Invocable {
name: string
description?: string
inputSchema?: z.AnyZodObject
callback: (args: Record<string, any>) => Promise<any>
}
function getFunctionSpec(invocable: Invocable): types.AIFunctionSpec {
const { name, description, inputSchema } = invocable
return {
@ -58,14 +67,11 @@ export function getFunctionSpec(invocable: Invocable): types.AIFunctionSpec {
}
}
/**
* Constraints:
* - params must be an object, so the underlying function should only expect a
* single parameter
* - for the return value type `T | MaybePromise<T>`, `T` must be serializable
* to JSON
*/
export function aiFunction({
export function aiFunction<
This,
Args extends any[],
Return extends Promise<any>
>({
name,
description,
inputSchema
@ -77,48 +83,38 @@ export function aiFunction({
// single parameter
inputSchema?: z.AnyZodObject
}) {
return function (
target: object,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const existingInvocables = getPrivateInvocables(target)
return (
targetMethod: (this: This, ...args: Args) => Return,
context: ClassMethodDecoratorContext<
This,
(this: This, ...args: Args) => Return
> & {
readonly metadata: {
invocables: Invocable[]
}
}
) => {
const methodName = String(context.name)
if (!context.metadata.invocables) {
context.metadata.invocables = []
}
existingInvocables.push({
propertyKey,
context.metadata.invocables.push({
name: name ?? methodName,
description,
name,
inputSchema
inputSchema,
callback: targetMethod
})
setPrivateInvocables(target, existingInvocables)
return targetMethod
return descriptor.get ?? descriptor.value
// function replacementMethod(this: This, ...args: Args): Return {
// console.log(`LOG: Entering method '${methodName}'.`)
// const result = targetMethod.call(this, ...args)
// console.log(`LOG: Exiting method '${methodName}'.`)
// return result
// }
// return replacementMethod
}
}
export function getInvocables(target: object): Invocable[] {
const invocables = getPrivateInvocables(target)
const namespace = target.constructor.name
return invocables.map((invocable) => ({
...invocable,
name: invocable.name ?? `${namespace}_${invocable.propertyKey}`,
callback: (target as any)[invocable.propertyKey].bind(target)
}))
}
interface PrivateInvocable {
propertyKey: string
name?: string
description?: string
inputSchema?: z.AnyZodObject
}
function getPrivateInvocables(target: object): PrivateInvocable[] {
return Reflect.getMetadata(invocableMetadataKey, target) ?? []
}
function setPrivateInvocables(target: object, invocables: PrivateInvocable[]) {
Reflect.defineMetadata(invocableMetadataKey, invocables, target)
}

Wyświetl plik

@ -1,4 +1,3 @@
export * from './fns.js'
export * from './function-set.js'
export * from './parse-structured-output.js'
export * from './services/index.js'

Wyświetl plik

@ -24,7 +24,7 @@ export class DexaClient {
this.ky = ky.extend({ prefixUrl: this.apiBaseUrl, timeout: 60_000 })
}
async generateResponse({ messages }: { messages: Prompt.Msg[] }) {
async askDexa({ messages }: { messages: Prompt.Msg[] }) {
return this.ky
.post('api/ask-dexa', {
json: {

Wyświetl plik

@ -1,9 +1,10 @@
export * from './clearbit.js'
export * from './clearbit-client.js'
export * from './dexa-client.js'
export * from './diffbot.js'
export * from './diffbot-client.js'
export * from './openai-client.js'
export * from './proxycurl-client.js'
export * from './scraper-client.js'
export * from './serpapi.js'
export * from './serper.js'
export * from './serpapi-client.js'
export * from './serper-client.js'
export * from './twitter-client.js'
export * from './weather.js'
export * from './weather-client.js'

Plik diff jest za duży Load Diff

Wyświetl plik

@ -2,25 +2,27 @@ import defaultKy, { type KyInstance } from 'ky'
import { assert, getEnv } from '../utils.js'
export type ScrapeResult = {
author: string
byline: string
/** The HTML for the main content of the page. */
content: string
description: string
imageUrl: string
lang: string
length: number
logoUrl: string
/** The text for the main content of the page in markdown format. */
markdownContent: string
publishedTime: string
/** The raw HTML response from the server. */
rawHtml: string
siteName: string
/** The text for the main content of the page. */
textContent: string
title: string
export namespace scraper {
export type ScrapeResult = {
author: string
byline: string
/** The HTML for the main content of the page. */
content: string
description: string
imageUrl: string
lang: string
length: number
logoUrl: string
/** The text for the main content of the page in markdown format. */
markdownContent: string
publishedTime: string
/** The raw HTML response from the server. */
rawHtml: string
siteName: string
/** The text for the main content of the page. */
textContent: string
title: string
}
}
/**
@ -56,7 +58,7 @@ export class ScraperClient {
}: {
timeout?: number
} = {}
): Promise<ScrapeResult> {
): Promise<scraper.ScrapeResult> {
return this.ky
.post('scrape', {
json: { url },

Wyświetl plik

@ -0,0 +1,21 @@
// https://github.com/microsoft/TypeScript/issues/53461
// symbol-polyfill.ts
declare global {
interface SymbolConstructor {
readonly metadata: unique symbol
}
}
;(Symbol as any).metadata ??= Symbol.for('Symbol.metadata')
const _metadata = Object.create(null)
if (typeof Symbol === 'function' && Symbol.metadata) {
Object.defineProperty(globalThis, Symbol.metadata, {
enumerable: true,
configurable: true,
writable: true,
value: _metadata
})
}

Wyświetl plik

@ -14,3 +14,105 @@ export interface AIToolSpec {
type: 'function'
function: AIFunctionSpec
}
/**
* Generic/default OpenAI message without any narrowing applied
*/
export interface Msg {
/** The contents of the message. `content` is required for all messages, and may be null for assistant messages with function calls. */
content: string | null
/** The role of the messages author. One of `system`, `user`, `assistant`, 'tool', or `function`. */
role: Msg.Role
/** The name and arguments of a function that should be called, as generated by the model. */
function_call?: Msg.Call.Function
/** The tool calls generated by the model, such as function calls. */
tool_calls?: Msg.Call.Tool[]
/**
* Tool call that this message is responding to.
*/
tool_call_id?: string
/**
* The name of the author of this message. `name` is required if role is
* `function`, and it should be the name of the function whose response is in the
* `content`. May contain a-z, A-Z, 0-9, and underscores, with a maximum length of
* 64 characters.
*/
name?: string
}
/** Narrowed ChatModel.Message types. */
export namespace Msg {
/** The possible roles for a message. */
export type Role = 'system' | 'user' | 'assistant' | 'function' | 'tool'
export namespace Call {
/** The name and arguments of a function that should be called, as generated by the model. */
export type Function = {
/** The arguments to call the function with, as generated by the model in JSON format. */
arguments: string
/** The name of the function to call. */
name: string
}
/** The tool calls generated by the model, such as function calls. */
export type Tool = {
/** The ID of the tool call. */
id: string
/** The type of the tool. Currently, only `function` is supported. */
type: 'function'
/** The function that the model called. */
function: Call.Function
}
}
/** Message with text content for the system. */
export type System = {
role: 'system'
content: string
name?: string
}
/** Message with text content from the user. */
export type User = {
role: 'user'
name?: string
content: string
}
/** Message with text content from the assistant. */
export type Assistant = {
role: 'assistant'
name?: string
content: string
}
/** Message with arguments to call a function. */
export type FuncCall = {
role: 'assistant'
name?: string
content: null
function_call: Call.Function
}
/** Message with the result of a function call. */
export type FuncResult = {
role: 'function'
name: string
content: string
}
/** Message with arguments to call one or more tools. */
export type ToolCall = {
role: 'assistant'
name?: string
content: null
tool_calls: Call.Tool[]
}
/** Message with the result of a tool call. */
export type ToolResult = {
role: 'tool'
tool_call_id: string
content: string
}
}

Wyświetl plik

@ -11,7 +11,6 @@ export function zodToJsonSchema(schema: z.ZodType): Record<string, unknown> {
'default',
'definitions',
'description',
'markdownDescription',
'additionalProperties'
'markdownDescription'
)
}