chatgpt-api/src/task.ts

109 wiersze
2.8 KiB
TypeScript
Czysty Zwykły widok Historia

2023-06-10 05:42:20 +00:00
import pRetry, { FailedAttemptError } from 'p-retry'
import { ZodRawShape, ZodTypeAny } from 'zod'
2023-05-26 19:06:39 +00:00
2023-06-09 17:44:02 +00:00
import * as errors from '@/errors'
2023-06-09 01:41:28 +00:00
import * as types from '@/types'
import { Agentic } from '@/agentic'
2023-05-26 19:06:39 +00:00
2023-05-27 00:36:52 +00:00
/**
* A `Task` is a typed, async function call that may be non-deterministic.
*
2023-06-06 22:20:20 +00:00
* Invoking a task is equivalent to sampling from a probability distribution.
*
2023-05-27 00:36:52 +00:00
* Examples of tasks include:
2023-06-02 06:26:22 +00:00
* - LLM calls
2023-06-06 22:20:20 +00:00
* - Chain of LLM calls
* - Retrieval task
2023-05-27 00:36:52 +00:00
* - API calls
* - Native function calls
2023-05-27 00:36:52 +00:00
* - Invoking sub-agents
*/
2023-06-02 06:26:22 +00:00
export abstract class BaseTask<
2023-05-26 19:06:39 +00:00
TInput extends ZodRawShape | ZodTypeAny = ZodTypeAny,
TOutput extends ZodRawShape | ZodTypeAny = ZodTypeAny
2023-05-26 19:06:39 +00:00
> {
protected _agentic: Agentic
2023-06-06 22:20:20 +00:00
protected _timeoutMs?: number
2023-06-09 17:44:02 +00:00
protected _retryConfig: types.RetryConfig
2023-06-01 01:53:09 +00:00
constructor(options: types.BaseTaskOptions) {
this._agentic = options.agentic
2023-05-26 19:16:13 +00:00
this._timeoutMs = options.timeoutMs
2023-06-09 17:44:02 +00:00
this._retryConfig = options.retryConfig ?? {
retries: 3,
strategy: 'default'
}
2023-05-26 19:06:39 +00:00
}
public get agentic(): Agentic {
return this._agentic
}
2023-06-01 01:53:09 +00:00
public abstract get inputSchema(): TInput
public abstract get outputSchema(): TOutput
2023-05-26 19:06:39 +00:00
2023-06-02 06:26:22 +00:00
// TODO
// public abstract get nameForModel(): string
// public abstract get nameForHuman(): string
// public abstract get descForModel(): string
// public abstract get descForHuman(): string
2023-06-01 01:53:09 +00:00
public retryConfig(retryConfig: types.RetryConfig) {
2023-05-26 19:16:13 +00:00
this._retryConfig = retryConfig
2023-05-26 19:06:39 +00:00
return this
}
2023-06-06 22:20:20 +00:00
public async call(
input?: types.ParsedData<TInput>
): Promise<types.ParsedData<TOutput>> {
const res = await this.callWithMetadata(input)
return res.result
2023-06-06 22:20:20 +00:00
}
public async callWithMetadata(
input?: types.ParsedData<TInput>
): Promise<types.TaskResponse<TOutput>> {
2023-06-10 05:42:20 +00:00
const ctx: types.TaskCallContext<TInput, TOutput> = {
2023-06-09 17:44:02 +00:00
input,
2023-06-10 05:42:20 +00:00
attemptNumber: 0,
metadata: {}
2023-06-09 17:44:02 +00:00
}
2023-06-10 05:42:20 +00:00
const result = await pRetry(() => this._call(ctx), {
...this._retryConfig,
onFailedAttempt: async (err: FailedAttemptError) => {
if (this._retryConfig.onFailedAttempt) {
await Promise.resolve(this._retryConfig.onFailedAttempt(err))
}
ctx.attemptNumber = err.attemptNumber + 1
2023-06-09 17:44:02 +00:00
if (err instanceof errors.ZodOutputValidationError) {
2023-06-10 05:42:20 +00:00
ctx.retryMessage = err.message
} else if (err instanceof errors.OutputValidationError) {
ctx.retryMessage = err.message
2023-06-09 17:44:02 +00:00
} else {
throw err
}
}
2023-06-10 05:42:20 +00:00
})
2023-06-09 17:44:02 +00:00
2023-06-10 05:42:20 +00:00
return {
result,
metadata: ctx.metadata
}
2023-06-06 22:20:20 +00:00
}
protected abstract _call(
2023-06-10 05:42:20 +00:00
ctx: types.TaskCallContext<TInput, TOutput>
): Promise<types.ParsedData<TOutput>>
2023-05-26 19:06:39 +00:00
// TODO
// abstract stream({
// input: TInput,
// onProgress: types.ProgressFunction
// }): Promise<TOutput>
}