diff --git a/docs/src/content/docs/reference/scripts/chat-participants.mdx b/docs/src/content/docs/reference/scripts/chat-participants.mdx
new file mode 100644
index 0000000000..cd63298df0
--- /dev/null
+++ b/docs/src/content/docs/reference/scripts/chat-participants.mdx
@@ -0,0 +1,47 @@
+---
+title: Chat Participants
+sidebar:
+ order: 50
+---
+import { Code } from '@astrojs/starlight/components';
+import scriptSource from "../../../../../../packages/sample/genaisrc/multi-turn.genai.js?raw"
+
+
+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.
+
+```js
+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.
+
+```js
+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.
+
+```js
+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.
+
+
diff --git a/packages/core/src/chat.ts b/packages/core/src/chat.ts
index b7c59d8adb..8f03dc6a2d 100644
--- a/packages/core/src/chat.ts
+++ b/packages/core/src/chat.ts
@@ -402,7 +402,6 @@ async function processChatMessage(
functions: ChatFunctionCallback[],
chatParticipants: ChatParticipant[],
schemas: Record,
- vars: Partial,
genVars: Record,
options: GenerationOptions
): Promise {
@@ -445,11 +444,7 @@ async function processChatMessage(
const { label } = participantOptions || {}
trace.startDetails(`🙋 participant ${label || ""}`)
- const ctx = createChatTurnGenerationContext(
- options,
- vars,
- trace
- )
+ const ctx = createChatTurnGenerationContext(options, trace)
await generator(ctx, structuredClone(messages))
const node = ctx.node
checkCancelled(cancellationToken)
@@ -578,7 +573,6 @@ export async function executeChatSession(
functions,
chatParticipants,
schemas,
- vars,
genVars,
genOptions
)
diff --git a/packages/core/src/promptcontext.ts b/packages/core/src/promptcontext.ts
index 1f46355247..8f33130ab7 100644
--- a/packages/core/src/promptcontext.ts
+++ b/packages/core/src/promptcontext.ts
@@ -198,7 +198,7 @@ export function createPromptContext(
}
const ctx = Object.freeze({
- ...createChatGenerationContext(options, env, trace),
+ ...createChatGenerationContext(options, trace),
script: () => {},
system: () => {},
env,
@@ -227,7 +227,7 @@ export function createPromptContext(
infoCb?.({ text: `run prompt ${label || ""}` })
const genOptions = mergeGenerationOptions(options, runOptions)
- const ctx = createChatGenerationContext(genOptions, vars, trace)
+ const ctx = createChatGenerationContext(genOptions, trace)
if (typeof generator === "string")
ctx.node.children.push(createTextNode(generator))
else await generator(ctx)
diff --git a/packages/core/src/runpromptcontext.ts b/packages/core/src/runpromptcontext.ts
index 2842031862..469cae28f3 100644
--- a/packages/core/src/runpromptcontext.ts
+++ b/packages/core/src/runpromptcontext.ts
@@ -22,10 +22,8 @@ import { resolveFileDataUri } from "./file"
export function createChatTurnGenerationContext(
options: GenerationOptions,
- vars: Partial,
trace: MarkdownTrace
): ChatTurnGenerationContext & { node: PromptNode } {
- const { cancellationToken, infoCb } = options || {}
const node: PromptNode = { children: [] }
const log = (...args: any[]) => {
@@ -115,10 +113,9 @@ export interface RunPromptContextNode extends ChatGenerationContext {
export function createChatGenerationContext(
options: GenerationOptions,
- vars: Partial,
trace: MarkdownTrace
): RunPromptContextNode {
- const turnCtx = createChatTurnGenerationContext(options, vars, trace)
+ const turnCtx = createChatTurnGenerationContext(options, trace)
const node = turnCtx.node
const defTool: (
diff --git a/packages/sample/genaisrc/multi-turn.genai.js b/packages/sample/genaisrc/multi-turn.genai.js
index 74bae0a09d..1b826081f2 100644
--- a/packages/sample/genaisrc/multi-turn.genai.js
+++ b/packages/sample/genaisrc/multi-turn.genai.js
@@ -3,10 +3,9 @@ script({
title: "Multi-turn conversation",
files: ["src/rag/markdown.md"],
system: ["system", "system.files"],
+ tests: {},
})
-def("FILE", env.files)
-
let turn = 0
defChatParticipant(
async (_, messages) => {
@@ -79,4 +78,5 @@ Answer the QUESTION using the contents in FILE.
{ label: "answerer" }
)
+def("FILE", env.files)
$`Generate a set of questions for the files to build a FAQ. Format one line per question in text.`