Skip to content

Commit 9d3483d

Browse files
authored
feat: reset context on each session (#55)
* feat * fix * print error message
1 parent 3df75f3 commit 9d3483d

2 files changed

Lines changed: 68 additions & 63 deletions

File tree

packages/cali/src/cli.ts

Lines changed: 65 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'dotenv/config'
55
import { execSync } from 'node:child_process'
66

77
import { createOpenAI } from '@ai-sdk/openai'
8-
import { confirm, log, outro, select, spinner, text } from '@clack/prompts'
8+
import { confirm, outro, select, spinner, text } from '@clack/prompts'
99
import { CoreMessage, generateText } from 'ai'
1010
import * as tools from 'cali-tools'
1111
import chalk from 'chalk'
@@ -19,11 +19,16 @@ const MessageSchema = z.union([
1919
z.object({ type: z.literal('select'), content: z.string(), options: z.array(z.string()) }),
2020
z.object({ type: z.literal('question'), content: z.string() }),
2121
z.object({ type: z.literal('confirmation'), content: z.string() }),
22-
z.object({ type: z.literal('end'), content: z.string() }),
22+
z.object({ type: z.literal('end') }),
2323
])
2424

2525
console.clear()
2626

27+
process.on('uncaughtException', (error) => {
28+
console.error(chalk.red(error.message))
29+
console.log(chalk.gray(error.stack))
30+
})
31+
2732
console.log(
2833
retro(`
2934
██████╗ █████╗ ██╗ ██╗
@@ -43,38 +48,39 @@ console.log(
4348
`)
4449
)
4550

46-
console.log()
47-
4851
const OPENAI_API_KEY =
4952
process.env.OPENAI_API_KEY ||
5053
(await (async () => {
51-
let apiKey: string | symbol
52-
do {
53-
apiKey = await text({
54-
message: dedent`
55-
${chalk.bold('Please provide your OpenAI API key.')}
56-
57-
To skip this message, set ${chalk.bold('OPENAI_API_KEY')} env variable, and run again.
58-
59-
You can do it in three ways:
60-
- by creating an ${chalk.bold('.env.local')} file (make sure to ${chalk.bold('.gitignore')} it)
61-
${chalk.gray(`\`\`\`
62-
OPENAI_API_KEY=<your-key>
63-
\`\`\`
64-
`)}
65-
- by passing it inline:
66-
${chalk.gray(`\`\`\`
67-
OPENAI_API_KEY=<your-key> npx cali
68-
\`\`\`
69-
`)}
70-
- by setting it as an env variable in your shell (e.g. in ~/.zshrc or ~/.bashrc):
71-
${chalk.gray(`\`\`\`
72-
export OPENAI_API_KEY=<your-key>
73-
\`\`\`
74-
`)},
75-
`,
76-
})
77-
} while (typeof apiKey !== 'string')
54+
const apiKey = await text({
55+
message: dedent`
56+
${chalk.bold('Please provide your OpenAI API key.')}
57+
58+
To skip this message, set ${chalk.bold('OPENAI_API_KEY')} env variable, and run again.
59+
60+
You can do it in three ways:
61+
- by creating an ${chalk.bold('.env.local')} file (make sure to ${chalk.bold('.gitignore')} it)
62+
${chalk.gray(`\`\`\`
63+
OPENAI_API_KEY=<your-key>
64+
\`\`\`
65+
`)}
66+
- by passing it inline:
67+
${chalk.gray(`\`\`\`
68+
OPENAI_API_KEY=<your-key> npx cali
69+
\`\`\`
70+
`)}
71+
- by setting it as an env variable in your shell (e.g. in ~/.zshrc or ~/.bashrc):
72+
${chalk.gray(`\`\`\`
73+
export OPENAI_API_KEY=<your-key>
74+
\`\`\`
75+
`)},
76+
`,
77+
validate: (value) => (value.length > 0 ? undefined : 'Please provide a valid answer.'),
78+
})
79+
80+
if (typeof apiKey === 'symbol') {
81+
outro(chalk.gray('Bye!'))
82+
process.exit(0)
83+
}
7884

7985
const save = await confirm({
8086
message: 'Do you want to save it for future runs in `.env.local`?',
@@ -94,26 +100,31 @@ const openai = createOpenAI({
94100
apiKey: OPENAI_API_KEY,
95101
})
96102

97-
const question = await text({
98-
message: 'What do you want to do today?',
99-
placeholder: 'e.g. "Build the app" or "See available simulators"',
100-
})
103+
async function startSession(): Promise<CoreMessage[]> {
104+
const question = await text({
105+
message: 'What do you want to do today?',
106+
placeholder: 'e.g. "Build the app" or "See available simulators"',
107+
validate: (value) => (value.length > 0 ? undefined : 'Please provide a valid answer.'),
108+
})
101109

102-
if (typeof question === 'symbol') {
103-
outro(chalk.gray('Bye!'))
104-
process.exit(0)
110+
if (typeof question === 'symbol') {
111+
outro(chalk.gray('Bye!'))
112+
process.exit(0)
113+
}
114+
115+
return [
116+
{
117+
role: 'system',
118+
content: 'What do you want to do today?',
119+
},
120+
{
121+
role: 'user',
122+
content: question,
123+
},
124+
]
105125
}
106126

107-
const messages: CoreMessage[] = [
108-
{
109-
role: 'system',
110-
content: 'What do you want to do today?',
111-
},
112-
{
113-
role: 'user',
114-
content: question,
115-
},
116-
]
127+
let messages = await startSession()
117128

118129
const s = spinner()
119130

@@ -195,20 +206,21 @@ while (true) {
195206
options: data.options.map((option) => ({ value: option, label: option })),
196207
})
197208
case 'question':
198-
return text({ message: data.content })
209+
return text({
210+
message: data.content,
211+
validate: (value) => (value.length > 0 ? undefined : 'Please provide a valid answer.'),
212+
})
199213
case 'confirmation': {
200214
return confirm({ message: data.content }).then((answer) => {
201215
return answer ? 'yes' : 'no'
202216
})
203217
}
204-
case 'end':
205-
log.step(data.content)
206218
}
207219
})()
208220

209221
if (typeof answer !== 'string') {
210-
outro(chalk.gray('Bye!'))
211-
break
222+
messages = await startSession()
223+
continue
212224
}
213225

214226
messages.push({

packages/cali/src/prompt.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export const reactNativePrompt = dedent`
1919
- If you need more information, ask a follow-up question.
2020
- Never build or run for multiple platforms simultaneously.
2121
- If user selects "Debug" mode, always start Metro bundler using "startMetro" tool.
22-
- Never end session, unless user confirms they do not want to continue.
2322
2423
ERROR HANDLING:
2524
- If a tool call returns an error, you must explain the error to the user and ask user if they want to try again:
@@ -43,7 +42,7 @@ export const reactNativePrompt = dedent`
4342
4443
- If user confirms, you must re-run the same tool.
4544
- Never ask user to perform the action manually. Instead, ask user to fix the error, so you can run the tool again.
46-
- If single tool fails more than 3 times, proceed with NEXT TASK.
45+
- If single tool fails more than 3 times, you must end the session.
4746
4847
RESPONSE FORMAT:
4948
- Your response must be a valid JSON object.
@@ -67,16 +66,10 @@ export const reactNativePrompt = dedent`
6766
"type": "confirmation",
6867
"content": "<question>"
6968
}
70-
- When you finish processing user task, you must ask user a confirmation if they want to continue with another task:
71-
{
72-
"type": "confirmation",
73-
"content": "<question>"
74-
}
75-
- If user does not want to continue, you must return "end" type.
69+
- When you finish processing user task, you must answer with:
7670
{
7771
"type": "end",
78-
"content": "<result>"
79-
}
72+
}
8073
8174
EXAMPLES:
8275
<example>

0 commit comments

Comments
 (0)