Skip to content

Commit 6faffc8

Browse files
committed
Add Example 7: shared $kind sub-discriminator pattern in prompt
The toolResult value appears on two variants (status=ok and status=error). Pydantic raises 'mapped to multiple choices' when using Field(discriminator='kind'). Added concrete example showing how to handle this: nest sub-variants by status, use plain union for the outer type when any value is duplicated.
1 parent d2306f2 commit 6faffc8

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

codegen-llm/src/prompts.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,51 @@ In Python, merge all properties into one BaseModel. The verifier flattens
314314
\`allOf\` during normalisation, so a flat model matches correctly.
315315
316316
317+
### Example 7: Shared \`$kind\` with sub-discriminator
318+
319+
Sometimes two variants share the same \`$kind\` value but differ by another
320+
field (e.g. \`status\`). You CANNOT use \`Field(discriminator='kind')\` when
321+
two variants have the same \`kind\` value — Pydantic will raise an error.
322+
323+
\`\`\`json
324+
{"anyOf": [
325+
{"properties": {"$kind": {"const": "toolResult"}, "status": {"const": "ok"}, "result": {}}, ...},
326+
{"properties": {"$kind": {"const": "toolResult"}, "status": {"const": "error"}, "error": {...}}, ...},
327+
{"properties": {"$kind": {"const": "output"}, ...}, ...}
328+
]}
329+
\`\`\`
330+
331+
Solution: nest the sub-discriminated variants into a union, then use the
332+
outer discriminator only on unique \`$kind\` values:
333+
334+
\`\`\`python
335+
class ToolResultOk(BaseModel):
336+
kind: Literal['toolResult'] = Field(alias='$kind')
337+
status: Literal['ok']
338+
invocationId: str
339+
result: Any
340+
model_config = ConfigDict(populate_by_name=True)
341+
342+
class ToolResultError(BaseModel):
343+
kind: Literal['toolResult'] = Field(alias='$kind')
344+
status: Literal['error']
345+
invocationId: str
346+
error: ToolResultErrorDetail
347+
model_config = ConfigDict(populate_by_name=True)
348+
349+
# Sub-discriminate by status (unique within this group)
350+
ToolResult = Annotated[ToolResultOk | ToolResultError, Field(discriminator='status')]
351+
352+
# For the outer union, do NOT use discriminator='kind' since
353+
# toolResult appears twice. Use a plain union instead:
354+
EvaluateInput = ToolResultOk | ToolResultError | OutputMessage | ...
355+
\`\`\`
356+
357+
If ALL \`$kind\` values are unique, you CAN use \`Field(discriminator='kind')\`.
358+
If ANY \`$kind\` value appears more than once, you MUST NOT use a \`kind\`
359+
discriminator — use a plain union instead.
360+
361+
317362
## What to generate
318363
319364
Write a complete Python package into: \`generated/\`

0 commit comments

Comments
 (0)