messagesWithInstructions function

List<ChatMessage> messagesWithInstructions(
  1. Iterable<ChatMessage> messages,
  2. String? instructions
)

Returns messages with instructions materialized as the leading system message.

M.E.AI carries system instructions out-of-band in ChatOptions.instructions; converting them into an in-band system message is the chat client's job (the extensions OpenAI client does the same). ChatFormats only render a system turn from an actual system-role message, so without this step the caller's instructions — including any a host framework contributes — are silently dropped from the prompt.

If the conversation already starts with a system message the two are merged into one (instructions first): Gemma's wire format has a single system turn, and a second system-role message mid-prompt would render as its own bogus turn.

Implementation

List<ChatMessage> messagesWithInstructions(
  Iterable<ChatMessage> messages,
  String? instructions,
) {
  final trimmed = instructions?.trim();
  final list = messages.toList();
  if (trimmed == null || trimmed.isEmpty) return list;

  ChatMessage system(String text) => ChatMessage(
    role: ChatRole.system,
    contents: <AIContent>[TextContent(text)],
  );

  if (list.isNotEmpty && list.first.role == ChatRole.system) {
    return <ChatMessage>[
      system('$trimmed\n\n${list.first.text}'),
      ...list.skip(1),
    ];
  }
  return <ChatMessage>[system(trimmed), ...list];
}