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

Wyświetl plik

@ -10,7 +10,6 @@ import { defaultLogger } from './logger'
import { defaultIDGeneratorFn, isFunction, isString } from './utils' import { defaultIDGeneratorFn, isFunction, isString } from './utils'
export class Agentic { export class Agentic {
// _taskMap: WeakMap<string, BaseTask<any, any>>
protected _ky: types.KyInstance protected _ky: types.KyInstance
protected _logger: types.Logger protected _logger: types.Logger
@ -103,7 +102,7 @@ export class Agentic {
return this._idGeneratorFn return this._idGeneratorFn
} }
openaiChatCompletion<TInput extends types.TaskInput = any>( openaiChatCompletion<TInput extends types.TaskInput = void>(
promptOrChatCompletionParams: promptOrChatCompletionParams:
| types.ChatMessageContent<TInput> | types.ChatMessageContent<TInput>
| SetOptional<types.OpenAIChatCompletionParamsInput<TInput>, 'model'>, | 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. * 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: promptOrChatCompletionParams:
| types.ChatMessageContent<TInput> | types.ChatMessageContent<TInput>
| SetOptional<types.OpenAIChatCompletionParamsInput<TInput>, 'model'>, | 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. * 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: promptOrChatCompletionParams:
| types.ChatMessageContent<TInput> | types.ChatMessageContent<TInput>
| SetOptional<types.OpenAIChatCompletionParamsInput<TInput>, 'model'>, | 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 { pino } from 'pino'
import pinoPretty from 'pino-pretty' import pinoPretty from 'pino-pretty'
import { getEnv } from './env'
export type Level = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' export type Level = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'
export type LevelWithSilent = Level | 'silent' export type LevelWithSilent = Level | 'silent'
@ -103,7 +105,7 @@ export interface Logger {
export const defaultLogger: Logger = pino( export const defaultLogger: Logger = pino(
{ {
level: process.env.LOG_LEVEL || 'info' level: getEnv('LOG_LEVEL', 'info')
}, },
pinoPretty({ pinoPretty({
sync: true, sync: true,

Wyświetl plik

@ -1,6 +1,8 @@
import logger from 'debug' import logger from 'debug'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { getEnv } from './env'
/** /**
* List of events that can occur within the library. * 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. * 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 let LOG_LEVEL: SeverityType = Severity.INFO
const logLevelEnv = getEnv('DEBUG_LOG_LEVEL')
if ( if (logLevelEnv && Severity[logLevelEnv.toUpperCase()] !== undefined) {
process.env.DEBUG_LOG_LEVEL && LOG_LEVEL = Severity[logLevelEnv.toUpperCase()]
Severity[process.env.DEBUG_LOG_LEVEL.toUpperCase()] !== undefined } else if (logLevelEnv) {
) { throw new Error(`Invalid value for LOG_LEVEL: ${logLevelEnv}`)
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}`)
} }
/** /**

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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