kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: add support for stop signal and use do-while
rodzic
646398d2aa
commit
f823da15af
|
@ -116,6 +116,11 @@ export type TwilioSendAndWaitOptions = {
|
|||
* A function to validate the reply message. If the function returns `true`, the reply is considered valid and the function will return the message. If the function returns `false`, the reply is considered invalid and the function will continue to wait for a reply until the timeout is reached.
|
||||
*/
|
||||
validate?: (message: TwilioConversationMessage) => boolean
|
||||
|
||||
/**
|
||||
* A stop signal from an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController), which can be used to abort retrying. More specifically, when `AbortController.abort(reason)` is called, the function will throw an error with the `reason` argument as the error message.
|
||||
*/
|
||||
stopSignal?: AbortSignal
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -242,14 +247,28 @@ export class TwilioConversationClient {
|
|||
recipientPhoneNumber,
|
||||
timeoutMs = DEFAULT_TWILIO_TIMEOUT_MS,
|
||||
intervalMs = DEFAULT_TWILIO_INTERVAL_MS,
|
||||
validate = () => true
|
||||
validate = () => true,
|
||||
stopSignal
|
||||
}: TwilioSendAndWaitOptions) {
|
||||
let aborted = false
|
||||
stopSignal?.addEventListener(
|
||||
'abort',
|
||||
() => {
|
||||
aborted = true
|
||||
},
|
||||
{ once: true }
|
||||
)
|
||||
|
||||
const { sid: conversationSid } = await this.createConversation(name)
|
||||
await this.addParticipant({ conversationSid, recipientPhoneNumber })
|
||||
await this.sendMessage({ conversationSid, text })
|
||||
const start = Date.now()
|
||||
let nUserMessages = 0
|
||||
while (Date.now() - start < timeoutMs) {
|
||||
do {
|
||||
if (aborted) {
|
||||
await this.deleteConversation(conversationSid)
|
||||
throw new Error('Aborted waiting for reply')
|
||||
}
|
||||
const response = await this.fetchMessages(conversationSid)
|
||||
if (response.messages.length > 1) {
|
||||
const candidates = response.messages.filter(
|
||||
|
@ -269,7 +288,8 @@ export class TwilioConversationClient {
|
|||
nUserMessages = candidates.length
|
||||
}
|
||||
await sleep(intervalMs)
|
||||
}
|
||||
} while (Date.now() - start < timeoutMs)
|
||||
|
||||
await this.deleteConversation(conversationSid)
|
||||
throw new Error('Reached timeout waiting for reply')
|
||||
}
|
||||
|
|
|
@ -101,3 +101,38 @@ test('TwilioConversationClient.sendAndWaitForReply', async (t) => {
|
|||
}
|
||||
)
|
||||
})
|
||||
|
||||
test('TwilioConversationClient.sendAndWaitForReply.stopSignal', async (t) => {
|
||||
if (
|
||||
!process.env.TWILIO_ACCOUNT_SID ||
|
||||
!process.env.TWILIO_AUTH_TOKEN ||
|
||||
!process.env.TWILIO_TEST_PHONE_NUMBER
|
||||
) {
|
||||
return t.pass()
|
||||
}
|
||||
|
||||
t.timeout(2 * 60 * 1000)
|
||||
const client = new TwilioConversationClient()
|
||||
|
||||
await t.throwsAsync(
|
||||
async () => {
|
||||
const controller = new AbortController()
|
||||
const promise = client.sendAndWaitForReply({
|
||||
recipientPhoneNumber: process.env.TWILIO_TEST_PHONE_NUMBER as string,
|
||||
text: 'Please confirm by replying with "yes" or "no".',
|
||||
name: 'wait-for-reply-test',
|
||||
validate: (message) =>
|
||||
['yes', 'no'].includes(message.body.toLowerCase()),
|
||||
timeoutMs: 10000, // 10 seconds
|
||||
intervalMs: 5000, // 5 seconds
|
||||
stopSignal: controller.signal
|
||||
})
|
||||
controller.abort()
|
||||
return promise
|
||||
},
|
||||
{
|
||||
instanceOf: Error,
|
||||
message: 'Aborted waiting for reply'
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
Ładowanie…
Reference in New Issue