kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
chore: minor refactors
rodzic
a1bd7ef101
commit
673aa18d25
|
@ -1,5 +1,5 @@
|
||||||
import * as types from '@/types'
|
import * as types from '@/types'
|
||||||
import { defaultOpenAIModel } from '@/constants'
|
import { DEFAULT_OPENAI_MODEL } from '@/constants'
|
||||||
import { OpenAIChatModel } from '@/llms/openai'
|
import { OpenAIChatModel } from '@/llms/openai'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -20,7 +20,6 @@ export class Agentic {
|
||||||
'provider' | 'model' | 'modelParams' | 'timeoutMs' | 'retryConfig'
|
'provider' | 'model' | 'modelParams' | 'timeoutMs' | 'retryConfig'
|
||||||
>
|
>
|
||||||
protected _defaultHumanFeedbackMechamism?: HumanFeedbackMechanism
|
protected _defaultHumanFeedbackMechamism?: HumanFeedbackMechanism
|
||||||
|
|
||||||
protected _idGeneratorFn: types.IDGeneratorFunction
|
protected _idGeneratorFn: types.IDGeneratorFunction
|
||||||
|
|
||||||
constructor(opts: {
|
constructor(opts: {
|
||||||
|
@ -41,7 +40,7 @@ export class Agentic {
|
||||||
|
|
||||||
this._openaiModelDefaults = {
|
this._openaiModelDefaults = {
|
||||||
provider: 'openai',
|
provider: 'openai',
|
||||||
model: defaultOpenAIModel,
|
model: DEFAULT_OPENAI_MODEL,
|
||||||
modelParams: {},
|
modelParams: {},
|
||||||
timeoutMs: 2 * 60000,
|
timeoutMs: 2 * 60000,
|
||||||
retryConfig: {
|
retryConfig: {
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
export const defaultOpenAIModel = 'gpt-3.5-turbo'
|
export const DEFAULT_OPENAI_MODEL = 'gpt-3.5-turbo'
|
||||||
export const defaultAnthropicModel = 'claude-instant-v1'
|
export const DEFAULT_ANTHROPIC_MODEL = 'claude-instant-v1'
|
||||||
export const BOT_NAME = 'Agentic Bot'
|
export const DEFAULT_BOT_NAME = 'Agentic Bot'
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as anthropic from '@anthropic-ai/sdk'
|
||||||
import { type SetOptional } from 'type-fest'
|
import { type SetOptional } from 'type-fest'
|
||||||
|
|
||||||
import * as types from '@/types'
|
import * as types from '@/types'
|
||||||
import { defaultAnthropicModel } from '@/constants'
|
import { DEFAULT_ANTHROPIC_MODEL } from '@/constants'
|
||||||
|
|
||||||
import { BaseChatModel } from './llm'
|
import { BaseChatModel } from './llm'
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export class AnthropicChatModel<
|
||||||
) {
|
) {
|
||||||
super({
|
super({
|
||||||
provider: 'anthropic',
|
provider: 'anthropic',
|
||||||
model: options.modelParams?.model || defaultAnthropicModel,
|
model: options.modelParams?.model || DEFAULT_ANTHROPIC_MODEL,
|
||||||
...options
|
...options
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { type SetOptional } from 'type-fest'
|
import { type SetOptional } from 'type-fest'
|
||||||
|
|
||||||
import * as types from '@/types'
|
import * as types from '@/types'
|
||||||
import { defaultOpenAIModel } from '@/constants'
|
import { DEFAULT_OPENAI_MODEL } from '@/constants'
|
||||||
|
|
||||||
import { BaseChatModel } from './llm'
|
import { BaseChatModel } from './llm'
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export class OpenAIChatModel<
|
||||||
) {
|
) {
|
||||||
super({
|
super({
|
||||||
provider: 'openai',
|
provider: 'openai',
|
||||||
model: options.modelParams?.model || defaultOpenAIModel,
|
model: options.modelParams?.model || DEFAULT_OPENAI_MODEL,
|
||||||
...options
|
...options
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,36 @@
|
||||||
import ky from 'ky'
|
import ky from 'ky'
|
||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
export const METAPHOR_BASE_URL = 'https://api.metaphor.systems'
|
export const METAPHOR_BASE_URL = 'https://api.metaphor.systems'
|
||||||
|
|
||||||
export type MetaphorSearchResult = {
|
// https://metaphorapi.readme.io/reference/search
|
||||||
author: string | null
|
export const MetaphorSearchInputSchema = z.object({
|
||||||
dateCreated: string | null
|
query: z.string(),
|
||||||
title: string | null
|
numResults: z.number().optional(),
|
||||||
score: number
|
useQueryExpansion: z.boolean().optional(),
|
||||||
url: string
|
includeDomains: z.array(z.string()).optional(),
|
||||||
}
|
excludeDomains: z.array(z.string()).optional(),
|
||||||
|
startCrawlDate: z.string().optional(),
|
||||||
|
endCrawlDate: z.string().optional(),
|
||||||
|
startPublishedDate: z.string().optional(),
|
||||||
|
endPublishedDate: z.string().optional()
|
||||||
|
})
|
||||||
|
|
||||||
export type MetaphorSearchResponse = {
|
export type MetaphorSearchInput = z.infer<typeof MetaphorSearchInputSchema>
|
||||||
results: MetaphorSearchResult[]
|
|
||||||
}
|
export const MetaphorSearchOutputSchema = z.object({
|
||||||
|
results: z.array(
|
||||||
|
z.object({
|
||||||
|
author: z.string().nullable(),
|
||||||
|
publishedDate: z.string().nullable(),
|
||||||
|
title: z.string().nullable(),
|
||||||
|
score: z.number(),
|
||||||
|
url: z.string()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export type MetaphorSearchOutput = z.infer<typeof MetaphorSearchOutputSchema>
|
||||||
|
|
||||||
export class MetaphorClient {
|
export class MetaphorClient {
|
||||||
apiKey: string
|
apiKey: string
|
||||||
|
@ -33,23 +51,14 @@ export class MetaphorClient {
|
||||||
this.baseUrl = baseUrl
|
this.baseUrl = baseUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
async search({
|
async search(params: MetaphorSearchInput) {
|
||||||
query,
|
|
||||||
numResults = 10
|
|
||||||
}: {
|
|
||||||
query: string
|
|
||||||
numResults?: number
|
|
||||||
}) {
|
|
||||||
return ky
|
return ky
|
||||||
.post(`${this.baseUrl}/search`, {
|
.post(`${this.baseUrl}/search`, {
|
||||||
headers: {
|
headers: {
|
||||||
'x-api-key': this.apiKey
|
'x-api-key': this.apiKey
|
||||||
},
|
},
|
||||||
json: {
|
json: params
|
||||||
query,
|
|
||||||
numResults
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.json<MetaphorSearchResponse>()
|
.json<MetaphorSearchOutput>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import ky, { KyResponse } from 'ky'
|
import ky, { type KyResponse } from 'ky'
|
||||||
|
|
||||||
import { BOT_NAME } from '@/constants'
|
import { DEFAULT_BOT_NAME } from '@/constants'
|
||||||
import { sleep } from '@/utils'
|
import { sleep } from '@/utils'
|
||||||
|
|
||||||
export const TWILIO_CONVERSATION_BASE_URL =
|
export const TWILIO_CONVERSATION_BASE_URL =
|
||||||
|
@ -131,17 +131,20 @@ export type TwilioSendAndWaitOptions = {
|
||||||
export class TwilioConversationClient {
|
export class TwilioConversationClient {
|
||||||
api: typeof ky
|
api: typeof ky
|
||||||
phoneNumber: string
|
phoneNumber: string
|
||||||
|
botName: string
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
accountSid = process.env.TWILIO_ACCOUNT_SID,
|
accountSid = process.env.TWILIO_ACCOUNT_SID,
|
||||||
authToken = process.env.TWILIO_AUTH_TOKEN,
|
authToken = process.env.TWILIO_AUTH_TOKEN,
|
||||||
phoneNumber = process.env.TWILIO_PHONE_NUMBER,
|
phoneNumber = process.env.TWILIO_PHONE_NUMBER,
|
||||||
baseUrl = TWILIO_CONVERSATION_BASE_URL
|
baseUrl = TWILIO_CONVERSATION_BASE_URL,
|
||||||
|
botName = DEFAULT_BOT_NAME
|
||||||
}: {
|
}: {
|
||||||
accountSid?: string
|
accountSid?: string
|
||||||
authToken?: string
|
authToken?: string
|
||||||
phoneNumber?: string
|
phoneNumber?: string
|
||||||
baseUrl?: string
|
baseUrl?: string
|
||||||
|
botName?: string
|
||||||
} = {}) {
|
} = {}) {
|
||||||
if (!accountSid || !authToken) {
|
if (!accountSid || !authToken) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -155,7 +158,9 @@ export class TwilioConversationClient {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.botName = botName
|
||||||
this.phoneNumber = phoneNumber
|
this.phoneNumber = phoneNumber
|
||||||
|
|
||||||
this.api = ky.create({
|
this.api = ky.create({
|
||||||
prefixUrl: baseUrl,
|
prefixUrl: baseUrl,
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -219,7 +224,7 @@ export class TwilioConversationClient {
|
||||||
}) {
|
}) {
|
||||||
const params = new URLSearchParams()
|
const params = new URLSearchParams()
|
||||||
params.set('Body', text)
|
params.set('Body', text)
|
||||||
params.set('Author', BOT_NAME)
|
params.set('Author', this.botName)
|
||||||
return this.api
|
return this.api
|
||||||
.post(`Conversations/${conversationSid}/Messages`, {
|
.post(`Conversations/${conversationSid}/Messages`, {
|
||||||
body: params
|
body: params
|
||||||
|
@ -284,7 +289,7 @@ export class TwilioConversationClient {
|
||||||
|
|
||||||
if (response.messages.length > 1) {
|
if (response.messages.length > 1) {
|
||||||
const candidates = response.messages.filter(
|
const candidates = response.messages.filter(
|
||||||
(message) => message.author !== BOT_NAME
|
(message) => message.author !== this.botName
|
||||||
)
|
)
|
||||||
const candidate = candidates[candidates.length - 1]
|
const candidate = candidates[candidates.length - 1]
|
||||||
|
|
||||||
|
@ -307,6 +312,6 @@ export class TwilioConversationClient {
|
||||||
} while (Date.now() - start < timeoutMs)
|
} while (Date.now() - start < timeoutMs)
|
||||||
|
|
||||||
await this.deleteConversation(conversationSid)
|
await this.deleteConversation(conversationSid)
|
||||||
throw new Error('Reached timeout waiting for reply')
|
throw new Error('Twilio timeout waiting for reply')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/task.ts
12
src/task.ts
|
@ -48,18 +48,6 @@ export abstract class BaseTask<TInput = void, TOutput = string> {
|
||||||
|
|
||||||
public abstract get name(): string
|
public abstract get name(): string
|
||||||
|
|
||||||
public serialize(): types.SerializedTask {
|
|
||||||
return {
|
|
||||||
_taskName: this.name
|
|
||||||
// inputSchema: this.inputSchema.serialize()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// public abstract deserialize<
|
|
||||||
// TInput extends ZodTypeAny = ZodTypeAny,
|
|
||||||
// TOutput extends ZodTypeAny = ZodTypeAny
|
|
||||||
// >(data: types.SerializedTask): BaseTask<TInput, TOutput>
|
|
||||||
|
|
||||||
// TODO: is this really necessary?
|
// TODO: is this really necessary?
|
||||||
public clone(): BaseTask<TInput, TOutput> {
|
public clone(): BaseTask<TInput, TOutput> {
|
||||||
// TODO: override in subclass if needed
|
// TODO: override in subclass if needed
|
||||||
|
|
|
@ -1,48 +1,21 @@
|
||||||
import { z } from 'zod'
|
import * as metaphor from '@/services/metaphor'
|
||||||
|
|
||||||
import * as types from '@/types'
|
import * as types from '@/types'
|
||||||
import { Agentic } from '@/agentic'
|
import { Agentic } from '@/agentic'
|
||||||
import { MetaphorClient } from '@/services/metaphor'
|
|
||||||
import { BaseTask } from '@/task'
|
import { BaseTask } from '@/task'
|
||||||
|
|
||||||
export const MetaphorSearchToolInputSchema = z.object({
|
|
||||||
query: z.string(),
|
|
||||||
numResults: z.number().optional()
|
|
||||||
})
|
|
||||||
|
|
||||||
export type MetaphorSearchToolInput = z.infer<
|
|
||||||
typeof MetaphorSearchToolInputSchema
|
|
||||||
>
|
|
||||||
|
|
||||||
export const MetaphorSearchToolOutputSchema = z.object({
|
|
||||||
results: z.array(
|
|
||||||
z.object({
|
|
||||||
author: z.string().nullable(),
|
|
||||||
dateCreated: z.string().nullable(),
|
|
||||||
title: z.string().nullable(),
|
|
||||||
score: z.number(),
|
|
||||||
url: z.string()
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
export type MetaphorSearchToolOutput = z.infer<
|
|
||||||
typeof MetaphorSearchToolOutputSchema
|
|
||||||
>
|
|
||||||
|
|
||||||
export class MetaphorSearchTool extends BaseTask<
|
export class MetaphorSearchTool extends BaseTask<
|
||||||
MetaphorSearchToolInput,
|
metaphor.MetaphorSearchInput,
|
||||||
MetaphorSearchToolOutput
|
metaphor.MetaphorSearchOutput
|
||||||
> {
|
> {
|
||||||
_metaphorClient: MetaphorClient
|
_metaphorClient: metaphor.MetaphorClient
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
agentic,
|
agentic,
|
||||||
metaphorClient = new MetaphorClient(),
|
metaphorClient = new metaphor.MetaphorClient(),
|
||||||
...rest
|
...rest
|
||||||
}: {
|
}: {
|
||||||
agentic: Agentic
|
agentic: Agentic
|
||||||
metaphorClient?: MetaphorClient
|
metaphorClient?: metaphor.MetaphorClient
|
||||||
} & types.BaseTaskOptions) {
|
} & types.BaseTaskOptions) {
|
||||||
super({
|
super({
|
||||||
agentic,
|
agentic,
|
||||||
|
@ -53,11 +26,11 @@ export class MetaphorSearchTool extends BaseTask<
|
||||||
}
|
}
|
||||||
|
|
||||||
public override get inputSchema() {
|
public override get inputSchema() {
|
||||||
return MetaphorSearchToolInputSchema
|
return metaphor.MetaphorSearchInputSchema
|
||||||
}
|
}
|
||||||
|
|
||||||
public override get outputSchema() {
|
public override get outputSchema() {
|
||||||
return MetaphorSearchToolOutputSchema
|
return metaphor.MetaphorSearchOutputSchema
|
||||||
}
|
}
|
||||||
|
|
||||||
public override get name(): string {
|
public override get name(): string {
|
||||||
|
@ -65,12 +38,9 @@ export class MetaphorSearchTool extends BaseTask<
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async _call(
|
protected override async _call(
|
||||||
ctx: types.TaskCallContext<MetaphorSearchToolInput>
|
ctx: types.TaskCallContext<metaphor.MetaphorSearchInput>
|
||||||
): Promise<MetaphorSearchToolOutput> {
|
): Promise<metaphor.MetaphorSearchOutput> {
|
||||||
// TODO: test required inputs
|
// TODO: test required inputs
|
||||||
return this._metaphorClient.search({
|
return this._metaphorClient.search(ctx.input!)
|
||||||
query: ctx.input!.query,
|
|
||||||
numResults: ctx.input!.numResults
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,13 +95,6 @@ export interface RetryConfig extends RetryOptions {
|
||||||
strategy?: string
|
strategy?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TaskError =
|
|
||||||
| 'timeout'
|
|
||||||
| 'provider'
|
|
||||||
| 'validation'
|
|
||||||
| 'unknown'
|
|
||||||
| string
|
|
||||||
|
|
||||||
export interface TaskResponseMetadata extends Record<string, any> {
|
export interface TaskResponseMetadata extends Record<string, any> {
|
||||||
// task info
|
// task info
|
||||||
taskName: string
|
taskName: string
|
||||||
|
|
Ładowanie…
Reference in New Issue