kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
fix: improve typing
rodzic
a84b7b191c
commit
e722c5b9d7
|
@ -3,28 +3,16 @@ import editor from '@inquirer/editor'
|
||||||
import input from '@inquirer/input'
|
import input from '@inquirer/input'
|
||||||
import select from '@inquirer/select'
|
import select from '@inquirer/select'
|
||||||
|
|
||||||
import { Agentic } from '@/agentic'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
HumanFeedbackMechanism,
|
HumanFeedbackMechanism,
|
||||||
HumanFeedbackOptions,
|
HumanFeedbackType,
|
||||||
UserActionMessages,
|
UserActionMessages,
|
||||||
UserActions
|
UserActions
|
||||||
} from './feedback'
|
} from './feedback'
|
||||||
|
|
||||||
export class HumanFeedbackMechanismCLI extends HumanFeedbackMechanism {
|
export class HumanFeedbackMechanismCLI<
|
||||||
constructor({
|
T extends HumanFeedbackType
|
||||||
agentic,
|
> extends HumanFeedbackMechanism<T> {
|
||||||
options
|
|
||||||
}: {
|
|
||||||
agentic: Agentic
|
|
||||||
options: HumanFeedbackOptions
|
|
||||||
}) {
|
|
||||||
super({ agentic, options })
|
|
||||||
this._agentic = agentic
|
|
||||||
this._options = options
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompt the user to select one of a list of options.
|
* Prompt the user to select one of a list of options.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Agentic } from '@/agentic'
|
import { Agentic } from '@/agentic'
|
||||||
import { BaseTask } from '@/task'
|
import { BaseTask } from '@/task'
|
||||||
import { TaskResponseMetadata } from '@/types'
|
|
||||||
|
|
||||||
import { HumanFeedbackMechanismCLI } from './cli'
|
import { HumanFeedbackMechanismCLI } from './cli'
|
||||||
|
|
||||||
|
@ -30,20 +29,18 @@ export const UserActionMessages: Record<UserActions, string> = {
|
||||||
*/
|
*/
|
||||||
export type HumanFeedbackType = 'confirm' | 'selectOne' | 'selectN'
|
export type HumanFeedbackType = 'confirm' | 'selectOne' | 'selectN'
|
||||||
|
|
||||||
type HumanFeedbackMechanismConstructor<T extends HumanFeedbackMechanism> = new (
|
type HumanFeedbackMechanismConstructor<T extends HumanFeedbackType> = new (
|
||||||
...args: any[]
|
...args: any[]
|
||||||
) => T
|
) => HumanFeedbackMechanism<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for human feedback.
|
* Options for human feedback.
|
||||||
*/
|
*/
|
||||||
export type HumanFeedbackOptions<
|
export type HumanFeedbackOptions<T extends HumanFeedbackType> = {
|
||||||
T extends HumanFeedbackMechanism = HumanFeedbackMechanism
|
|
||||||
> = {
|
|
||||||
/**
|
/**
|
||||||
* What type of feedback to request.
|
* What type of feedback to request.
|
||||||
*/
|
*/
|
||||||
type?: HumanFeedbackType
|
type?: T
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the user can bail out of the feedback loop.
|
* Whether the user can bail out of the feedback loop.
|
||||||
|
@ -66,17 +63,75 @@ export type HumanFeedbackOptions<
|
||||||
mechanism?: HumanFeedbackMechanismConstructor<T>
|
mechanism?: HumanFeedbackMechanismConstructor<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class HumanFeedbackMechanism {
|
export interface BaseHumanFeedbackMetadata {
|
||||||
|
/**
|
||||||
|
* Edited output by the user (if applicable).
|
||||||
|
*/
|
||||||
|
editedOutput?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation left by the user (if applicable).
|
||||||
|
*/
|
||||||
|
annotation?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HumanFeedbackConfirmMetadata
|
||||||
|
extends BaseHumanFeedbackMetadata {
|
||||||
|
/**
|
||||||
|
* The type of feedback requested.
|
||||||
|
*/
|
||||||
|
type: 'confirm'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user accepted the output.
|
||||||
|
*/
|
||||||
|
accepted: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HumanFeedbackSelectOneMetadata
|
||||||
|
extends BaseHumanFeedbackMetadata {
|
||||||
|
/**
|
||||||
|
* The type of feedback requested.
|
||||||
|
*/
|
||||||
|
type: 'selectOne'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selected output.
|
||||||
|
*/
|
||||||
|
chosen: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HumanFeedbackSelectNMetadata
|
||||||
|
extends BaseHumanFeedbackMetadata {
|
||||||
|
/**
|
||||||
|
* The type of feedback requested.
|
||||||
|
*/
|
||||||
|
type: 'selectN'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selected outputs.
|
||||||
|
*/
|
||||||
|
selected: any[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FeedbackTypeToMetadata<T extends HumanFeedbackType> =
|
||||||
|
T extends 'confirm'
|
||||||
|
? HumanFeedbackConfirmMetadata
|
||||||
|
: T extends 'selectOne'
|
||||||
|
? HumanFeedbackSelectOneMetadata
|
||||||
|
: HumanFeedbackSelectNMetadata
|
||||||
|
|
||||||
|
export abstract class HumanFeedbackMechanism<T extends HumanFeedbackType> {
|
||||||
protected _agentic: Agentic
|
protected _agentic: Agentic
|
||||||
|
|
||||||
protected _options: HumanFeedbackOptions
|
protected _options: Required<HumanFeedbackOptions<T>>
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
agentic,
|
agentic,
|
||||||
options
|
options
|
||||||
}: {
|
}: {
|
||||||
agentic: Agentic
|
agentic: Agentic
|
||||||
options: HumanFeedbackOptions
|
options: Required<HumanFeedbackOptions<T>>
|
||||||
}) {
|
}) {
|
||||||
this._agentic = agentic
|
this._agentic = agentic
|
||||||
this._options = options
|
this._options = options
|
||||||
|
@ -95,7 +150,7 @@ export abstract class HumanFeedbackMechanism {
|
||||||
choices: UserActions[]
|
choices: UserActions[]
|
||||||
): Promise<UserActions>
|
): Promise<UserActions>
|
||||||
|
|
||||||
public async interact(response: any, metadata: TaskResponseMetadata) {
|
public async interact(response: any): Promise<FeedbackTypeToMetadata<T>> {
|
||||||
const stringified = JSON.stringify(response, null, 2)
|
const stringified = JSON.stringify(response, null, 2)
|
||||||
const msg = [
|
const msg = [
|
||||||
'The following output was generated:',
|
'The following output was generated:',
|
||||||
|
@ -125,33 +180,33 @@ export abstract class HumanFeedbackMechanism {
|
||||||
choices.push(UserActions.Exit)
|
choices.push(UserActions.Exit)
|
||||||
}
|
}
|
||||||
|
|
||||||
const feedback =
|
const choice =
|
||||||
choices.length === 1
|
choices.length === 1
|
||||||
? UserActions.Select
|
? UserActions.Select
|
||||||
: await this.askUser(msg, choices)
|
: await this.askUser(msg, choices)
|
||||||
|
|
||||||
metadata.feedback = {}
|
const feedback: Record<string, any> = {}
|
||||||
|
|
||||||
switch (feedback) {
|
switch (choice) {
|
||||||
case UserActions.Accept:
|
case UserActions.Accept:
|
||||||
metadata.feedback.accepted = true
|
feedback.accepted = true
|
||||||
break
|
break
|
||||||
|
|
||||||
case UserActions.Edit: {
|
case UserActions.Edit: {
|
||||||
const editedOutput = await this.edit(stringified)
|
const editedOutput = await this.edit(stringified)
|
||||||
metadata.feedback.editedOutput = editedOutput
|
feedback.editedOutput = editedOutput
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case UserActions.Decline:
|
case UserActions.Decline:
|
||||||
metadata.feedback.accepted = false
|
feedback.accepted = false
|
||||||
break
|
break
|
||||||
|
|
||||||
case UserActions.Select:
|
case UserActions.Select:
|
||||||
if (this._options.type === 'selectN') {
|
if (this._options.type === 'selectN') {
|
||||||
metadata.feedback.selected = await this.selectN(response)
|
feedback.selected = await this.selectN(response)
|
||||||
} else if (this._options.type === 'selectOne') {
|
} else if (this._options.type === 'selectOne') {
|
||||||
metadata.feedback.chosen = await this.selectOne(response)
|
feedback.chosen = await this.selectOne(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -160,21 +215,23 @@ export abstract class HumanFeedbackMechanism {
|
||||||
throw new Error('Exiting...')
|
throw new Error('Exiting...')
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unexpected feedback: ${feedback}`)
|
throw new Error(`Unexpected choice: ${choice}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._options.annotations) {
|
if (this._options.annotations) {
|
||||||
const annotation = await this.annotate()
|
const annotation = await this.annotate()
|
||||||
if (annotation) {
|
if (annotation) {
|
||||||
metadata.feedback.annotation = annotation
|
feedback.annotation = annotation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return feedback as FeedbackTypeToMetadata<T>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function withHumanFeedback<T, U>(
|
export function withHumanFeedback<T, U, V extends HumanFeedbackType>(
|
||||||
task: BaseTask<T, U>,
|
task: BaseTask<T, U>,
|
||||||
options: HumanFeedbackOptions = {}
|
options: HumanFeedbackOptions<V> = {}
|
||||||
) {
|
) {
|
||||||
task = task.clone()
|
task = task.clone()
|
||||||
|
|
||||||
|
@ -182,7 +239,7 @@ export function withHumanFeedback<T, U>(
|
||||||
const instanceDefaults = task.agentic.humanFeedbackDefaults
|
const instanceDefaults = task.agentic.humanFeedbackDefaults
|
||||||
|
|
||||||
// Use Object.assign to merge the options, instance defaults, and hard-coded defaults
|
// Use Object.assign to merge the options, instance defaults, and hard-coded defaults
|
||||||
const finalOptions: HumanFeedbackOptions = Object.assign(
|
const finalOptions: HumanFeedbackOptions<V> = Object.assign(
|
||||||
{
|
{
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
bail: false,
|
bail: false,
|
||||||
|
@ -212,8 +269,9 @@ export function withHumanFeedback<T, U>(
|
||||||
task.callWithMetadata = async function (input?: T) {
|
task.callWithMetadata = async function (input?: T) {
|
||||||
const response = await originalCall(input)
|
const response = await originalCall(input)
|
||||||
|
|
||||||
// Process the response and add feedback to metadata
|
const feedback = await feedbackMechanism.interact(response.result)
|
||||||
await feedbackMechanism.interact(response.result, response.metadata)
|
|
||||||
|
response.metadata = { ...response.metadata, feedback }
|
||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,14 @@ import { SlackClient } from '@/services/slack'
|
||||||
import {
|
import {
|
||||||
HumanFeedbackMechanism,
|
HumanFeedbackMechanism,
|
||||||
HumanFeedbackOptions,
|
HumanFeedbackOptions,
|
||||||
|
HumanFeedbackType,
|
||||||
UserActionMessages,
|
UserActionMessages,
|
||||||
UserActions
|
UserActions
|
||||||
} from './feedback'
|
} from './feedback'
|
||||||
|
|
||||||
export class HumanFeedbackMechanismSlack extends HumanFeedbackMechanism {
|
export class HumanFeedbackMechanismSlack<
|
||||||
|
T extends HumanFeedbackType
|
||||||
|
> extends HumanFeedbackMechanism<T> {
|
||||||
private slackClient: SlackClient
|
private slackClient: SlackClient
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
|
@ -16,7 +19,7 @@ export class HumanFeedbackMechanismSlack extends HumanFeedbackMechanism {
|
||||||
options
|
options
|
||||||
}: {
|
}: {
|
||||||
agentic: Agentic
|
agentic: Agentic
|
||||||
options: HumanFeedbackOptions
|
options: Required<HumanFeedbackOptions<T>>
|
||||||
}) {
|
}) {
|
||||||
super({ agentic, options })
|
super({ agentic, options })
|
||||||
this.slackClient = new SlackClient()
|
this.slackClient = new SlackClient()
|
||||||
|
|
|
@ -4,11 +4,14 @@ import { TwilioConversationClient } from '@/services/twilio-conversation'
|
||||||
import {
|
import {
|
||||||
HumanFeedbackMechanism,
|
HumanFeedbackMechanism,
|
||||||
HumanFeedbackOptions,
|
HumanFeedbackOptions,
|
||||||
|
HumanFeedbackType,
|
||||||
UserActionMessages,
|
UserActionMessages,
|
||||||
UserActions
|
UserActions
|
||||||
} from './feedback'
|
} from './feedback'
|
||||||
|
|
||||||
export class HumanFeedbackMechanismTwilio extends HumanFeedbackMechanism {
|
export class HumanFeedbackMechanismTwilio<
|
||||||
|
T extends HumanFeedbackType
|
||||||
|
> extends HumanFeedbackMechanism<T> {
|
||||||
private twilioClient: TwilioConversationClient
|
private twilioClient: TwilioConversationClient
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
|
@ -16,7 +19,7 @@ export class HumanFeedbackMechanismTwilio extends HumanFeedbackMechanism {
|
||||||
options
|
options
|
||||||
}: {
|
}: {
|
||||||
agentic: Agentic
|
agentic: Agentic
|
||||||
options: HumanFeedbackOptions
|
options: Required<HumanFeedbackOptions<T>>
|
||||||
}) {
|
}) {
|
||||||
super({ agentic, options })
|
super({ agentic, options })
|
||||||
this.twilioClient = new TwilioConversationClient()
|
this.twilioClient = new TwilioConversationClient()
|
||||||
|
|
Ładowanie…
Reference in New Issue