Skip to content

Chat Participants

The defChatParticipant allows to register a function that can add new user messages in the chat sequence. This allows to create multi-turn chat, or to simulate a conversation with multiple participants.

let turn = 0
defChatParticipant((_, messages) => {
if (++turn === 1) _.$`Are you sure?`
})

In the example above, the defChatParticipant function is used to register a function that will be called every time a new message is added to the chat.

The function receives two arguments: the first argument is the Chat object, and the second argument is the list of messages that have been added to the chat since the last call to the function.

defChatParticipant(async (_, messages) => {
const text = messages.at(-1).content
...
})

Tracking turns

The participant will be called on every turn so it is important to keep track of the turns to avoid infinite loops.

let turn = 0
defChatParticipant((_, messages) => {
if (++turn === 1) _.$`Are you sure?`
})

Example: QA generator

This script uses a multi-turn chat to generate questions, answers and validate the quality of the answers.

qa-gen.genai.mjs
script({
model: "small",
title: "Multi-turn conversation",
files: ["src/rag/markdown.md"],
system: ["system", "system.files"],
tests: {},
})
def("FILE", env.files)
$`Generate a set of questions for the files to build a FAQ.`
// turn 2
let turn = 0
defChatParticipant(
async (ctx, messages) => {
turn++
if (turn <= 1) {
const text = messages.at(-1).content
const questions =
text
?.split("\n")
.map((q) => q.trim())
.filter((q) => q.length > 0) || []
ctx.$`Here is the list of answers to the questions in the file.
## Task 1:
Validate the quality of the answer.
## Task 2:
Write the question/answers pairs for each file in a "<filename>.qt.jsonl" file
using the JSONL format:
\`\`\`\`markdown
File: <filename>.qt.jsonl
\`\`\`
${JSONL.stringify([
{ q: "<question1>", a: "<answer1>" },
{ q: "<question2>", a: "<answer2>" },
])}
...
\`\`\`
\`\`\`\`
### Questions:
`
for (const question of questions) {
const res = await runPrompt(
(_) => {
_.def("FILE", env.files)
_.def("QUESTION", question)
_.$`
## Roles
You are an expert educator at explaining concepts simply.
## Task
Answer the QUESTION using the contents in FILE.
## Instructions
- Use information in FILE exclusively.
- Be concise.
- Use simple language.
- use gitmojis.
`
},
{ label: question }
)
ctx.$`
- question: ${question}`
ctx.fence(res.text)
ctx.$`\n\n`
}
}
},
{ label: "answerer" }
)