feat: add getEnv function

Travis Fischer 2023-06-19 17:57:47 -07:00
rodzic d8fb25f9c2
commit bbe66bd6fa
14 zmienionych plików z 77 dodań i 56 usunięć

Wyświetl plik

@ -1,13 +1,7 @@
{
"parser": "@typescript-eslint/parser",
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"plugins": [
"@typescript-eslint",
"eslint-plugin-tsdoc"
],
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"plugins": ["@typescript-eslint", "eslint-plugin-tsdoc"],
"root": true,
"env": {
"browser": false,
@ -38,47 +32,39 @@
"error",
{
"blankLine": "always",
"prev": [
"block",
"block-like"
],
"prev": ["block", "block-like"],
"next": "*"
},
{
"blankLine": "always",
"prev": "*",
"next": [
"block",
"block-like"
]
"next": ["block", "block-like"]
},
{
"blankLine": "any",
"prev": [
"singleline-const",
"singleline-let",
"expression"
],
"next": [
"block",
"block-like"
]
"prev": ["singleline-const", "singleline-let", "expression"],
"next": ["block", "block-like"]
}
],
"tsdoc/syntax": "warn"
},
"overrides": [
{
"files": [
"*.tsx"
],
"files": ["*.tsx"],
"rules": {
"no-undef": "off"
}
},
{
// disable process.env for framework source files
"files": "src/**/*.ts",
"rules": {
"no-process-env": "error"
}
}
],
"settings": {},
"globals": {
"__DEV__": true
}
}
}

Wyświetl plik

@ -10,7 +10,6 @@ import { defaultLogger } from './logger'
import { defaultIDGeneratorFn, isFunction, isString } from './utils'
export class Agentic {
// _taskMap: WeakMap<string, BaseTask<any, any>>
protected _ky: types.KyInstance
protected _logger: types.Logger
@ -103,7 +102,7 @@ export class Agentic {
return this._idGeneratorFn
}
openaiChatCompletion<TInput extends types.TaskInput = any>(
openaiChatCompletion<TInput extends types.TaskInput = void>(
promptOrChatCompletionParams:
| types.ChatMessageContent<TInput>
| SetOptional<types.OpenAIChatCompletionParamsInput<TInput>, 'model'>,
@ -148,7 +147,7 @@ export class Agentic {
/**
* Shortcut for creating an OpenAI chat completion call with the `gpt-3.5-turbo` model.
*/
gpt3<TInput extends types.TaskInput = any>(
gpt3<TInput extends types.TaskInput = void>(
promptOrChatCompletionParams:
| types.ChatMessageContent<TInput>
| SetOptional<types.OpenAIChatCompletionParamsInput<TInput>, 'model'>,
@ -194,7 +193,7 @@ export class Agentic {
/**
* Shortcut for creating an OpenAI chat completion call with the `gpt-4` model.
*/
gpt4<TInput extends types.TaskInput = any>(
gpt4<TInput extends types.TaskInput = void>(
promptOrChatCompletionParams:
| types.ChatMessageContent<TInput>
| SetOptional<types.OpenAIChatCompletionParamsInput<TInput>, 'model'>,

15
src/env.ts 100644
Wyświetl plik

@ -0,0 +1,15 @@
export function getEnv(
name: string,
defaultValue?: string
): string | undefined {
try {
return (
(typeof process !== 'undefined'
? // eslint-disable-next-line no-process-env
process.env?.[name]
: undefined) ?? defaultValue
)
} catch (e) {
return defaultValue
}
}

Wyświetl plik

@ -1,6 +1,8 @@
import { pino } from 'pino'
import pinoPretty from 'pino-pretty'
import { getEnv } from './env'
export type Level = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'
export type LevelWithSilent = Level | 'silent'
@ -103,7 +105,7 @@ export interface Logger {
export const defaultLogger: Logger = pino(
{
level: process.env.LOG_LEVEL || 'info'
level: getEnv('LOG_LEVEL', 'info')
},
pinoPretty({
sync: true,

Wyświetl plik

@ -1,6 +1,8 @@
import logger from 'debug'
import { v4 as uuidv4 } from 'uuid'
import { getEnv } from './env'
/**
* List of events that can occur within the library.
*/
@ -26,14 +28,12 @@ type SeverityType = (typeof Severity)[keyof typeof Severity]
* Define minimum LOG_LEVEL, defaulting to Severity.INFO if not provided or if an invalid value is provided. Any events below that level won't be logged to the console.
*/
let LOG_LEVEL: SeverityType = Severity.INFO
const logLevelEnv = getEnv('DEBUG_LOG_LEVEL')
if (
process.env.DEBUG_LOG_LEVEL &&
Severity[process.env.DEBUG_LOG_LEVEL.toUpperCase()] !== undefined
) {
LOG_LEVEL = Severity[process.env.DEBUG_LOG_LEVEL.toUpperCase()]
} else if (process.env.DEBUG_LOG_LEVEL) {
throw new Error(`Invalid value for LOG_LEVEL: ${process.env.DEBUG_LOG_LEVEL}`)
if (logLevelEnv && Severity[logLevelEnv.toUpperCase()] !== undefined) {
LOG_LEVEL = Severity[logLevelEnv.toUpperCase()]
} else if (logLevelEnv) {
throw new Error(`Invalid value for LOG_LEVEL: ${logLevelEnv}`)
}
/**

Wyświetl plik

@ -1,5 +1,7 @@
import defaultKy from 'ky'
import { getEnv } from '@/env'
export const BING_API_BASE_URL = 'https://api.bing.microsoft.com'
export interface BingWebSearchQuery {
@ -241,7 +243,7 @@ export class BingWebSearchClient {
apiBaseUrl: string
constructor({
apiKey = process.env.BING_API_KEY,
apiKey = getEnv('BING_API_KEY'),
apiBaseUrl = BING_API_BASE_URL,
ky = defaultKy
}: {

Wyświetl plik

@ -2,6 +2,7 @@ import defaultKy from 'ky'
import { AbortError } from 'p-retry'
import pThrottle from 'p-throttle'
import { getEnv } from '@/env'
import { throttleKy } from '@/utils'
export const DIFFBOT_API_BASE_URL = 'https://api.diffbot.com'
@ -334,7 +335,7 @@ export class DiffbotClient {
apiKnowledgeGraphBaseUrl: string
constructor({
apiKey = process.env.DIFFBOT_API_KEY,
apiKey = getEnv('DIFFBOT_API_KEY'),
apiBaseUrl = DIFFBOT_API_BASE_URL,
apiKnowledgeGraphBaseUrl = DIFFBOT_KNOWLEDGE_GRAPH_API_BASE_URL,
timeoutMs = 30_000,

Wyświetl plik

@ -1,5 +1,7 @@
import defaultKy from 'ky'
import { getEnv } from '@/env'
export const METAPHOR_API_BASE_URL = 'https://api.metaphor.systems'
/**
@ -119,7 +121,7 @@ export class MetaphorClient {
readonly apiBaseUrl: string
constructor({
apiKey = process.env.METAPHOR_API_KEY,
apiKey = getEnv('METAPHOR_API_KEY'),
apiBaseUrl = METAPHOR_API_BASE_URL,
ky = defaultKy
}: {

Wyświetl plik

@ -1,5 +1,7 @@
import defaultKy from 'ky'
import { getEnv } from '@/env'
/**
* Base URL endpoint for the Novu API.
*/
@ -110,7 +112,7 @@ export class NovuClient {
* Novu API client constructor.
*/
constructor({
apiKey = process.env.NOVU_API_KEY,
apiKey = getEnv('NOVU_API_KEY'),
apiBaseUrl = NOVU_API_BASE_URL,
ky = defaultKy
}: {

Wyświetl plik

@ -1,5 +1,7 @@
import defaultKy from 'ky'
import { getEnv } from '@/env'
/**
* All types have been exported from the `serpapi` package, which we're
* not using directly because it is bloated and has compatibility issues.
@ -642,7 +644,7 @@ export class SerpAPIClient {
params: Partial<SerpAPIParams>
constructor({
apiKey = process.env.SERPAPI_API_KEY ?? process.env.SERP_API_KEY,
apiKey = getEnv('SERPAPI_API_KEY') ?? getEnv('SERP_API_KEY'),
apiBaseUrl = SERPAPI_BASE_URL,
ky = defaultKy,
...params

Wyświetl plik

@ -1,5 +1,6 @@
import defaultKy from 'ky'
import { getEnv } from '@/env'
import { sleep } from '@/utils'
export const SLACK_API_BASE_URL = 'https://slack.com/api'
@ -261,9 +262,9 @@ export class SlackClient {
protected defaultChannel?: string
constructor({
apiKey = process.env.SLACK_API_KEY,
apiKey = getEnv('SLACK_API_KEY'),
baseUrl = SLACK_API_BASE_URL,
defaultChannel = process.env.SLACK_DEFAULT_CHANNEL,
defaultChannel = getEnv('SLACK_DEFAULT_CHANNEL'),
ky = defaultKy
}: {
apiKey?: string

Wyświetl plik

@ -1,6 +1,7 @@
import defaultKy from 'ky'
import { DEFAULT_BOT_NAME } from '@/constants'
import { getEnv } from '@/env'
import { chunkMultipleStrings, chunkString, sleep } from '@/utils'
export const TWILIO_CONVERSATION_API_BASE_URL =
@ -208,11 +209,12 @@ export class TwilioConversationClient {
defaultRecipientPhoneNumber?: string
constructor({
accountSid = process.env.TWILIO_ACCOUNT_SID,
authToken = process.env.TWILIO_AUTH_TOKEN,
phoneNumber = process.env.TWILIO_PHONE_NUMBER,
defaultRecipientPhoneNumber = process.env
.TWILIO_DEFAULT_RECIPIENT_PHONE_NUMBER,
accountSid = getEnv('TWILIO_ACCOUNT_SID'),
authToken = getEnv('TWILIO_AUTH_TOKEN'),
phoneNumber = getEnv('TWILIO_PHONE_NUMBER'),
defaultRecipientPhoneNumber = getEnv(
'TWILIO_DEFAULT_RECIPIENT_PHONE_NUMBER'
),
apiBaseUrl = TWILIO_CONVERSATION_API_BASE_URL,
botName = DEFAULT_BOT_NAME,
ky = defaultKy

Wyświetl plik

@ -1,5 +1,7 @@
import defaultKy from 'ky'
import { getEnv } from '@/env'
export const WEATHER_API_BASE_URL = 'https://api.weatherapi.com/v1'
interface CurrentWeatherResponse {
@ -75,7 +77,7 @@ export class WeatherClient {
apiBaseUrl: string
constructor({
apiKey = process.env.WEATHER_API_KEY,
apiKey = getEnv('WEATHER_API_KEY'),
apiBaseUrl = WEATHER_API_BASE_URL,
ky = defaultKy
}: {

Wyświetl plik

@ -18,8 +18,8 @@ import { defaultIDGeneratorFn, isValidTaskIdentifier } from './utils'
*
* Examples of tasks include:
* - LLM calls
* - Chain of LLM calls
* - Retrieval task
* - Chains of LLM calls
* - Retrieval tasks
* - API calls
* - Native function calls
* - Invoking sub-agents
@ -94,6 +94,10 @@ export abstract class BaseTask<
return this
}
/**
* Ensures that this task is configured correctly. `validate` will be called
* automatically before `task.call` or `task.callWithMetadata` are invoked.
*/
public validate() {
if (!this._agentic) {
throw new Error(
@ -241,6 +245,7 @@ export abstract class BaseTask<
(err as any).name === 'TimeoutError'
) {
// TODO
return
} else if ((err.cause as any)?.code === 'UND_ERR_HEADERS_TIMEOUT') {
// TODO: This is a pretty common OpenAI error, and I think it either has
// to do with OpenAI's servers being flaky or the combination of Node.js