fix: update feedback implementation

Philipp Burckhardt 2023-06-04 11:31:03 -04:00
rodzic 294011e410
commit 0a4b9ad39b
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: A2C3BCA4F31D1DDD
5 zmienionych plików z 282 dodań i 259 usunięć

Wyświetl plik

@ -0,0 +1,32 @@
import 'dotenv/config'
import { OpenAIClient } from 'openai-fetch'
import { z } from 'zod'
import { Agentic, HumanFeedbackSelect } from '../src'
async function main() {
const openai = new OpenAIClient({ apiKey: process.env.OPENAI_API_KEY! })
const ai = new Agentic({ openai })
const jokes = ai
.gpt3(`Tell me {{num}} jokes about {{topic}}`)
.input(
z.object({
topic: z.string(),
num: z.number().int().default(5).optional()
})
)
.output(z.array(z.string()))
.modelParams({ temperature: 0.9 })
const feedback = new HumanFeedbackSelect(z.string())
let out = await jokes.call({ topic: 'statisticians' })
let hf = await feedback.call(out)
while (!hf.accepted) {
out = await jokes.call({ topic: 'statisticians' })
hf = await feedback.call(out)
}
console.log(hf.results)
}
main()

Wyświetl plik

@ -2,30 +2,32 @@ import 'dotenv/config'
import { OpenAIClient } from 'openai-fetch'
import { z } from 'zod'
import { Agentic, HumanFeedback } from '../src'
import { Agentic, HumanFeedbackSingle } from '../src'
async function main() {
const openai = new OpenAIClient({ apiKey: process.env.OPENAI_API_KEY! })
const ai = new Agentic({ openai })
const feedback = new HumanFeedback()
let retry = true
while (retry) {
const out = await ai
.gpt3(`Give me {{numFacts}} random facts about {{topic}}`)
.input(
z.object({
topic: z.string(),
numFacts: z.number().int().default(5).optional()
})
)
.output(z.object({ facts: z.array(z.string()) }))
.modelParams({ temperature: 0.9 })
.call({ topic: 'cats' })
const topicFacts = ai
.gpt3(`Give me {{numFacts}} random facts about {{topic}}`)
.input(
z.object({
topic: z.string(),
numFacts: z.number().int().default(5).optional()
})
)
.output(z.object({ facts: z.array(z.string()) }))
.modelParams({ temperature: 0.9 })
retry = await feedback.process(out).requestFeedback()
const feedback = new HumanFeedbackSingle(topicFacts.outputSchema)
let out = await topicFacts.call({ topic: 'cats' })
let hf = await feedback.call(out)
while (!hf.accepted) {
out = await topicFacts.call({ topic: 'cats' })
hf = await feedback.call(out)
}
console.log(feedback.getResult())
console.log(hf.result)
}
main()

Wyświetl plik

@ -39,8 +39,10 @@
},
"dependencies": {
"@anthropic-ai/sdk": "^0.4.3",
"@inquirer/checkbox": "^1.3.0",
"@inquirer/editor": "^1.1.0",
"@inquirer/select": "^1.2.0",
"handlebars": "^4.7.7",
"inquirer": "^9.2.6",
"js-tiktoken": "^1.0.6",
"jsonrepair": "^3.1.0",
"ky": "^0.33.3",

Wyświetl plik

@ -8,12 +8,18 @@ dependencies:
'@anthropic-ai/sdk':
specifier: ^0.4.3
version: 0.4.3
'@inquirer/checkbox':
specifier: ^1.3.0
version: 1.3.0
'@inquirer/editor':
specifier: ^1.1.0
version: 1.1.0
'@inquirer/select':
specifier: ^1.2.0
version: 1.2.0
handlebars:
specifier: ^4.7.7
version: 4.7.7
inquirer:
specifier: ^9.2.6
version: 9.2.6
js-tiktoken:
specifier: ^1.0.6
version: 1.0.6
@ -537,6 +543,60 @@ packages:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
dev: true
/@inquirer/checkbox@1.3.0:
resolution: {integrity: sha512-kfYE5BH7vO0j2IwSgxzDmKPzQm/OpLnIZEEbOetYM+k4+YKTbSqeqCu7VZl3d8/rtotgJQc7gb8u2pIVeJh3Mg==}
engines: {node: '>=14.18.0'}
dependencies:
'@inquirer/core': 2.0.0
'@inquirer/type': 1.1.0
ansi-escapes: 4.3.2
chalk: 4.1.2
figures: 3.2.0
dev: false
/@inquirer/core@2.0.0:
resolution: {integrity: sha512-NnLGihYWEFVdFIoEDPwGO0jB5phuNcxTUHSNq5geyiOVQOnWNuX9x2rhPPeiikE/5fNXIBmqojD0+PiD9whtXw==}
engines: {node: '>=14.18.0'}
dependencies:
'@inquirer/type': 1.1.0
ansi-escapes: 4.3.2
chalk: 4.1.2
cli-spinners: 2.9.0
cli-width: 4.0.0
figures: 3.2.0
mute-stream: 1.0.0
run-async: 3.0.0
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 6.2.0
dev: false
/@inquirer/editor@1.1.0:
resolution: {integrity: sha512-ll6NfzutAuzRwNELERhECZCnAIzb2DdnRaNwtJ3Gfy6MrQBdYpFzGLwDyxB8+yf2iJoMOmsKWnzGbmvWNvSUhw==}
engines: {node: '>=14.18.0'}
dependencies:
'@inquirer/core': 2.0.0
'@inquirer/type': 1.1.0
chalk: 4.1.2
external-editor: 3.1.0
dev: false
/@inquirer/select@1.2.0:
resolution: {integrity: sha512-2CqhtE40GFmRXDFzJeMvSowKcO2/yvIzgSpL44+Hl/SAO/1FJgmHNAFGBuqX0RbohYPnSpF8eftgiy16fA3RJw==}
engines: {node: '>=14.18.0'}
dependencies:
'@inquirer/core': 2.0.0
'@inquirer/type': 1.1.0
ansi-escapes: 4.3.2
chalk: 4.1.2
figures: 3.2.0
dev: false
/@inquirer/type@1.1.0:
resolution: {integrity: sha512-XMaorygt2o/mXinZg/OOz6d3JKuV3o4jRc/3KDiVPeKLLkjiO4iJErbLKtKn+Od2ZC2lbiFQkrIuloVpEubisA==}
engines: {node: '>=14.18.0'}
dev: false
/@ioredis/commands@1.2.0:
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
dev: true
@ -1030,14 +1090,6 @@ packages:
engines: {node: '>=8'}
dev: true
/bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
dependencies:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
dev: false
/blueimp-md5@2.19.0:
resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==}
dev: true
@ -1060,13 +1112,6 @@ packages:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
/buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
dev: false
/bundle-require@4.0.1(esbuild@0.17.19):
resolution: {integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@ -1147,6 +1192,7 @@ packages:
/chalk@5.2.0:
resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
dev: true
/chardet@0.7.0:
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
@ -1202,6 +1248,7 @@ packages:
engines: {node: '>=8'}
dependencies:
restore-cursor: 3.1.0
dev: true
/cli-spinners@2.9.0:
resolution: {integrity: sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==}
@ -1238,11 +1285,6 @@ packages:
wrap-ansi: 7.0.0
dev: true
/clone@1.0.4:
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
engines: {node: '>=0.8'}
dev: false
/cluster-key-slot@1.1.2:
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
engines: {node: '>=0.10.0'}
@ -1391,12 +1433,6 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
/defaults@1.0.4:
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
dependencies:
clone: 1.0.4
dev: false
/define-properties@1.2.0:
resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
engines: {node: '>= 0.4'}
@ -1575,7 +1611,6 @@ packages:
/escape-string-regexp@1.0.5:
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'}
dev: true
/escape-string-regexp@2.0.0:
resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
@ -1590,6 +1625,7 @@ packages:
/escape-string-regexp@5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
dev: true
/eslint-scope@5.1.1:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
@ -1781,12 +1817,20 @@ packages:
reusify: 1.0.4
dev: true
/figures@3.2.0:
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
engines: {node: '>=8'}
dependencies:
escape-string-regexp: 1.0.5
dev: false
/figures@5.0.0:
resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==}
engines: {node: '>=14'}
dependencies:
escape-string-regexp: 5.0.0
is-unicode-supported: 1.3.0
dev: true
/file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
@ -2097,10 +2141,6 @@ packages:
safer-buffer: 2.1.2
dev: false
/ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: false
/ignore-by-default@2.1.0:
resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==}
engines: {node: '>=10 <11 || >=12 <13 || >=14'}
@ -2143,27 +2183,7 @@ packages:
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
/inquirer@9.2.6:
resolution: {integrity: sha512-y71l237eJJKS4rl7sQcEUiMhrR0pB/ZnRMMTxLpjJhWL4hdWCT03a6jJnC1w6qIPSRZWEozuieGt3v7XaEJYFw==}
engines: {node: '>=14.18.0'}
dependencies:
ansi-escapes: 4.3.2
chalk: 5.2.0
cli-cursor: 3.1.0
cli-width: 4.0.0
external-editor: 3.1.0
figures: 5.0.0
lodash: 4.17.21
mute-stream: 1.0.0
ora: 5.4.1
run-async: 3.0.0
rxjs: 7.8.1
string-width: 4.2.3
strip-ansi: 6.0.1
through: 2.3.8
wrap-ansi: 6.2.0
dev: false
dev: true
/internal-slot@1.0.5:
resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
@ -2272,11 +2292,6 @@ packages:
is-extglob: 2.1.1
dev: true
/is-interactive@1.0.0:
resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
engines: {node: '>=8'}
dev: false
/is-negative-zero@2.0.2:
resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
engines: {node: '>= 0.4'}
@ -2382,14 +2397,10 @@ packages:
has-tostringtag: 1.0.0
dev: true
/is-unicode-supported@0.1.0:
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
engines: {node: '>=10'}
dev: false
/is-unicode-supported@1.3.0:
resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==}
engines: {node: '>=12'}
dev: true
/is-weakref@1.0.2:
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
@ -2610,14 +2621,7 @@ packages:
/lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
/log-symbols@4.1.0:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'}
dependencies:
chalk: 4.1.2
is-unicode-supported: 0.1.0
dev: false
dev: true
/log-update@4.0.0:
resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
@ -2725,6 +2729,7 @@ packages:
/mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
dev: true
/mimic-fn@4.0.0:
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
@ -2908,6 +2913,7 @@ packages:
engines: {node: '>=6'}
dependencies:
mimic-fn: 2.1.0
dev: true
/onetime@6.0.0:
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
@ -2935,21 +2941,6 @@ packages:
word-wrap: 1.2.3
dev: true
/ora@5.4.1:
resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
engines: {node: '>=10'}
dependencies:
bl: 4.1.0
chalk: 4.1.2
cli-cursor: 3.1.0
cli-spinners: 2.9.0
is-interactive: 1.0.0
is-unicode-supported: 0.1.0
log-symbols: 4.1.0
strip-ansi: 6.0.1
wcwidth: 1.0.1
dev: false
/os-tmpdir@1.0.2:
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
engines: {node: '>=0.10.0'}
@ -3252,15 +3243,6 @@ packages:
type-fest: 1.4.0
dev: true
/readable-stream@3.6.2:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
dependencies:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
dev: false
/readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
@ -3334,6 +3316,7 @@ packages:
dependencies:
onetime: 5.1.2
signal-exit: 3.0.7
dev: true
/retry@0.13.1:
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
@ -3379,10 +3362,7 @@ packages:
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
dependencies:
tslib: 2.5.2
/safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: false
dev: true
/safe-regex-test@1.0.0:
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
@ -3460,6 +3440,7 @@ packages:
/signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: true
/signal-exit@4.0.2:
resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==}
@ -3641,12 +3622,6 @@ packages:
es-abstract: 1.21.2
dev: true
/string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
dependencies:
safe-buffer: 5.2.1
dev: false
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
@ -3753,6 +3728,7 @@ packages:
/through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: true
/time-zone@1.0.0:
resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==}
@ -3813,6 +3789,7 @@ packages:
/tslib@2.5.2:
resolution: {integrity: sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==}
dev: true
/tsup@6.7.0(typescript@5.0.4):
resolution: {integrity: sha512-L3o8hGkaHnu5TdJns+mCqFsDBo83bJ44rlK7e6VdanIvpea4ArPcU3swWGsLVbXak1PqQx/V+SSmFPujBK+zEQ==}
@ -3950,10 +3927,6 @@ packages:
punycode: 2.3.0
dev: true
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: false
/validate-npm-package-license@3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
dependencies:
@ -3961,12 +3934,6 @@ packages:
spdx-expression-parse: 3.0.1
dev: true
/wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
dependencies:
defaults: 1.0.4
dev: false
/webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
dev: false

Wyświetl plik

@ -1,36 +1,65 @@
import { checkbox, editor, select } from '@inquirer/prompts'
import checkbox from '@inquirer/checkbox'
import editor from '@inquirer/editor'
import select from '@inquirer/select'
import { ZodTypeAny, z } from 'zod'
import * as types from './../types'
import { BaseTaskCallBuilder } from './../task'
enum UserActions {
Accept = 'accept',
Edit = 'edit',
Decline = 'decline',
Select = 'select'
}
/**
* Actions the user can take in the feedback selection prompt.
*/
const UserActions = {
Accept: 'accept',
Edit: 'edit',
Decline: 'decline',
Select: 'select',
Exit: 'exit'
} as const
const UserActionMessages = {
type UserActions = (typeof UserActions)[keyof typeof UserActions]
/**
* Messages to display to the user for each action.
*/
const UserActionMessages: Record<UserActions, string> = {
[UserActions.Accept]: 'Accept inputs',
[UserActions.Edit]: 'Edit (open in editor)',
[UserActions.Decline]: 'Decline',
[UserActions.Select]: 'Select inputs to keep'
[UserActions.Select]: 'Select inputs to keep',
[UserActions.Exit]: 'Exit'
}
export const FeedbackSingleInputSchema = <T extends ZodTypeAny>(choice: T) =>
z.object({
choice
/**
* Prompt the user to select one of a list of options.
*/
async function askUser(
message: string,
choices: UserActions[]
): Promise<UserActions> {
return await select({
message,
choices: choices.map((choice) => ({
name: UserActionMessages[choice],
value: choice
}))
})
}
/**
* Output schema when prompting the user to accept, edit, or decline a single input.
*/
export const FeedbackSingleOutputSchema = <T extends ZodTypeAny>(result: T) =>
z.object({
result: result,
accepted: z.boolean()
})
/**
* Prompt the user to accept, edit, or decline a single input.
*/
export class HumanFeedbackSingle<
T extends ZodTypeAny = ZodTypeAny
T extends ZodTypeAny
> extends BaseTaskCallBuilder<ZodTypeAny, ZodTypeAny> {
private choiceSchema: T
@ -40,64 +69,59 @@ export class HumanFeedbackSingle<
}
public get inputSchema() {
return FeedbackSingleInputSchema(this.choiceSchema)
return this.choiceSchema
}
public get outputSchema() {
return FeedbackSingleOutputSchema(this.choiceSchema)
}
private async handleChoice(
input: types.ParsedData<typeof this.inputSchema>
): Promise<types.ParsedData<typeof this.outputSchema>> {
const feedback = await select({
message: [
'The following input was generated:',
JSON.stringify(input.choice, null, 2),
'What would you like to do?'
].join('\n'),
choices: [
{
name: UserActionMessages[UserActions.Accept],
value: UserActions.Accept
},
{
name: UserActionMessages[UserActions.Edit],
value: UserActions.Edit
},
{
name: UserActionMessages[UserActions.Decline],
value: UserActions.Decline
}
]
})
switch (feedback) {
case UserActions.Edit: {
// Open the completion in the user's default editor
const editedInput = await editor({
message: 'Edit the input:',
default: JSON.stringify(input.choice)
})
return {
result: this.choiceSchema.parse(JSON.parse(editedInput)),
accepted: true
}
}
case UserActions.Decline:
return { result: null, accepted: false }
case UserActions.Accept:
return { result: input, accepted: true }
default:
throw new Error('Invalid feedback choice')
private actionHandlers = {
[UserActions.Accept]: (
input: types.ParsedData<typeof this.inputSchema>
) => ({ result: input, accepted: true }),
[UserActions.Edit]: async (
input: types.ParsedData<typeof this.inputSchema>
) => {
const editedInput = await editor({
message: 'Edit the input:',
default: JSON.stringify(input)
})
return this.outputSchema.parse({
result: JSON.parse(editedInput),
accepted: true
})
},
[UserActions.Decline]: () => ({ result: null, accepted: false }),
[UserActions.Exit]: () => {
throw new Error('Exiting...')
}
}
/**
* Prompts the user to give feedback for the given input and handles their response.
*/
public async call(
input: types.ParsedData<typeof this.inputSchema>
): Promise<types.ParsedData<typeof this.outputSchema>> {
try {
input = this.inputSchema.parse(input)
return this.handleChoice(input)
const msg = [
'The following input was generated:',
JSON.stringify(input, null, 2),
'What would you like to do?'
].join('\n')
const feedback = await askUser(msg, [
UserActions.Accept,
UserActions.Edit,
UserActions.Decline,
UserActions.Exit
])
const handler = this.actionHandlers[feedback]
if (!handler) {
throw new Error(`Unexpected feedback: ${feedback}`)
}
return handler(input)
} catch (err) {
console.error('Error parsing input:', err)
throw err
@ -105,19 +129,20 @@ export class HumanFeedbackSingle<
}
}
export const FeedbackSelectInputSchema = <T extends ZodTypeAny>(choice: T) =>
z.object({
choices: z.array(choice)
})
/**
* Output schema when prompting the user to accept, select from, edit, or decline a list of inputs.
*/
export const FeedbackSelectOutputSchema = <T extends ZodTypeAny>(result: T) =>
z.object({
results: z.array(result),
accepted: z.boolean()
})
/**
* Prompt the user to accept, select from, edit, or decline a list of inputs.
*/
export class HumanFeedbackSelect<
T extends ZodTypeAny = ZodTypeAny
T extends ZodTypeAny
> extends BaseTaskCallBuilder<ZodTypeAny, ZodTypeAny> {
private choiceSchema: T
@ -127,81 +152,76 @@ export class HumanFeedbackSelect<
}
public get inputSchema() {
return FeedbackSelectInputSchema(this.choiceSchema)
return z.array(this.choiceSchema)
}
public get outputSchema() {
return FeedbackSelectOutputSchema(this.choiceSchema)
}
private async handleChoices(
input: types.ParsedData<typeof this.inputSchema>
): Promise<types.ParsedData<typeof this.outputSchema>> {
// Case: input is an array of strings
const feedback = await select({
message: [
'The following inputs were generated:',
...input.choices.map(
(choice, index) => `${index + 1}. ${JSON.stringify(choice, null, 2)}`
),
'What would you like to do?'
].join('\n'),
choices: [
{
name: UserActionMessages[UserActions.Accept],
value: UserActions.Accept
},
{
name: UserActionMessages[UserActions.Edit],
value: UserActions.Edit
},
{
name: UserActionMessages[UserActions.Decline],
value: UserActions.Decline
},
{
name: UserActionMessages[UserActions.Select],
value: UserActions.Select
}
]
})
switch (feedback) {
case UserActions.Edit: {
const edited = await editor({
message: 'Edit the input:',
default: JSON.stringify(input.choices, null, 2)
})
return { results: JSON.parse(edited), accepted: true }
}
case UserActions.Select: {
const choices = input.choices.map((completion) => ({
name: completion,
value: completion
}))
const chosen = await checkbox({
message: 'Pick items to keep:',
choices: [...choices]
})
if (chosen.length === 0) {
return { results: [], accepted: false }
}
return { results: chosen, accepted: true }
}
case UserActions.Decline:
return { results: [], accepted: false }
case UserActions.Accept:
return { results: input.choices, accepted: true }
default:
throw new Error('Invalid feedback choice')
private actionHandlers = {
[UserActions.Accept]: (
input: types.ParsedData<typeof this.inputSchema>
) => ({ results: input, accepted: true }),
[UserActions.Edit]: async (
input: types.ParsedData<typeof this.inputSchema>
) => {
const editedInput = await editor({
message: 'Edit the input:',
default: JSON.stringify(input, null, 2)
})
return this.outputSchema.parse({
results: JSON.parse(editedInput),
accepted: true
})
},
[UserActions.Select]: async (
input: types.ParsedData<typeof this.inputSchema>
) => {
const choices = input.map((completion) => ({
name: completion,
value: completion
}))
const chosen = await checkbox({
message: 'Pick items to keep:',
choices,
pageSize: choices.length
})
return { results: chosen.length === 0 ? [] : chosen, accepted: true }
},
[UserActions.Decline]: () => ({ results: [], accepted: false }),
[UserActions.Exit]: () => {
throw new Error('Exiting...')
}
}
/**
* Prompts the user to give feedback for the given list of inputs and handles their response.
*/
public async call(
input: types.ParsedData<typeof this.inputSchema>
): Promise<types.ParsedData<typeof this.outputSchema>> {
try {
input = this.inputSchema.parse(input)
return this.handleChoices(input)
const message = [
'The following inputs were generated:',
...input.map(
(choice, index) => `${index + 1}. ${JSON.stringify(choice, null, 2)}`
),
'What would you like to do?'
].join('\n')
const feedback = await askUser(message, [
UserActions.Accept,
UserActions.Select,
UserActions.Edit,
UserActions.Decline,
UserActions.Exit
])
const handler = this.actionHandlers[feedback]
if (!handler) {
throw new Error(`Unexpected feedback: ${feedback}`)
}
return handler(input)
} catch (err) {
console.error('Error parsing input:', err)
throw err