Skip to content

Conversation

@csells
Copy link
Contributor

@csells csells commented Dec 18, 2025

Description

fixes #626

Adds the following types ported from dartantic_interface and migrated to json_schema_builder:

  • Part (base class)
  • TextPart
  • DataPart (for images/binary data)
  • LinkPart (for URLs)
  • ToolPart (for tool calls and results)
  • ToolPartKind (enum: call, result)
  • ChatMessage
  • ChatMessageRole (enum: system, user, model)
  • ToolDefinition (name, description, inputSchema but no call implementation)

Pre-launch Checklist

  • I read the [Flutter Style Guide] recently, and have followed its advice.
  • I signed the [CLA].
  • I read the [Contributors Guide].
  • [n/a] I have added sample code updates to the [changelog].
  • I updated/added relevant documentation (doc comments with ///).

@csells
Copy link
Contributor Author

csells commented Dec 18, 2025

fyi: @gspencergoog @polina-c @sethladd

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new package genai_primitives by porting several types from dartantic_interface. The changes include new data models for chat messages, message parts (text, data, links, tools), and tool definitions, along with a comprehensive example and unit tests. The overall structure is good, but I've found several critical issues with equality checks and hashCode implementations that could lead to incorrect behavior, particularly when using these objects in hash-based collections. Additionally, there are some concerns with JSON serialization and a dependency on a private API. My review comments provide specific suggestions to address these points.

csells and others added 7 commits December 18, 2025 06:45
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
}

/// The role of a message author.
enum ChatMessageRole {
Copy link
Collaborator

@polina-c polina-c Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add more details to doc strings for enum and its items?

I can represent a confused user here:

  • doc for enum is saying that each item is a role of a message author, while doc for each item is describing type of message, not author

  • can you elaborate what is 'system'?

  • documentation is saying 'from', but not 'to'. Is it correct that system always send messages to model? If yes, should we specify it here? And the same about model: is it correct that model's messages are intended to be handled by system and then system will show to the user whatever is intended for user?

  • or my assumptions above are completely wrong and the enum relates to difference between 'user prompt' and 'system prompt' somehow?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe in this library instead of ChatMessage having field ChatMessageRole role, it make sense for it to have the field 'String type', so that every dependent can define their set of message types.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option:

class ChatMessage<T>{
  ...
  final T type;
  ...
}

Then users will be able to pass their enums for the message type. Maybe some of them will have more than one model and more than one system.

Copy link
Collaborator

@polina-c polina-c Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or, we can remove type completely, so that users just derive from ChatMessage and add whatever fields they want to add. Or users can compose ChatMessage into another object, that contains envelope information.

This seems to be cleanest option for me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll elaborate on what the enums mean, but across all of the LLM APIs (and I've built against most of them by now, certainly all of the major ones), it always boils down to role (user or system or model|assistant) and parts. Anything more than that is over engineering, imo.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think having roles itemized makes this library too opinionated.

I would remove role from the message completely, allowing clients to define the roles in their systems.

If you disagree let's merge this as is and have this discussion outside of this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's talk after the merge.

final ToolPartKind kind;

/// The unique identifier for this tool interaction.
final String id;
Copy link
Collaborator

@polina-c polina-c Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming it to interactionId, to avoid confusion and make it clear how to name this id, when it is copied outside of this class?
Is it correct that id of tool call is expected to be equal to id of tool call result? If yes, should it be documented here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. that's correct. I'll update the name and the docs.

@polina-c
Copy link
Collaborator

Thank you! It looks good. Left some naming and documentation related comments.

@csells
Copy link
Contributor Author

csells commented Dec 18, 2025

Yes you're correct about the tool result id matching the tool can id. I like the idea of updating the name and the docs to reflect that, although I don't know what that name should be. I'll provide an update ASAP.

final Map<String, dynamic>? arguments;

/// The result of a tool execution (null for calls).
final dynamic result;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use Object? instead of dynamic everywhere?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I second that. Dynamic turns off type checking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what kind of type checking do we get with Object? the standard JSON in/out in Dart is Map<String, dynamic> -- shouldn't we stick with that? I'm open to changing to Object? if I can understand the reason to vary from the Dart SOP.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are debates in Dash team if Dart should change the standard.
It is verified that Map<String, Object?> does not break standard json serialization.

With Object you get some minimal static analysis, with dynamic you can invoke whatever field you want.

There are lints that restrict dynamic and we use them.

@polina-c
Copy link
Collaborator

polina-c commented Dec 18, 2025

Yes you're correct about the tool result id matching the tool can id. I like the idea of updating the name and the docs to reflect that, although I don't know what that name should be. I'll provide an update ASAP.

I suggest interactionId.

@polina-c
Copy link
Collaborator

polina-c commented Dec 18, 2025

@csells, I raised many questions about minor details.

There are options how to proceed:

  1. I can just merge your PR, then figure out the details in the follow up PRs, then publish the package.
  2. We can figure out the details on this PR.

If you want to actively participate in discussion, let's go with (2).
Otherwise, let's proceed with (1), where you will be optional reviewer for the follow up PRs.

@polina-c
Copy link
Collaborator

Yes you're correct about the tool result id matching the tool can id. I like the idea of updating the name and the docs to reflect that, although I don't know what that name should be. I'll provide an update ASAP.

I suggest interactionId.

Or 'requestId'?

csells and others added 3 commits December 20, 2025 13:19
…oolName` for clarity, and enhance `ChatMessageRole` documentation."
…ble fields and new client properties. Also downstream updates required a new version of dartantic.
gspencergoog and others added 23 commits December 22, 2025 13:10
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…oolName` for clarity, and enhance `ChatMessageRole` documentation."
…ble fields and new client properties. Also downstream updates required a new version of dartantic.
@polina-c
Copy link
Collaborator

Landed!

Thanks to @andrewkolos for the fast fix!

Minor suggestion about this PR: how about using callId instead of interactionId to reduce number of terms in the package?

@csells
Copy link
Contributor Author

csells commented Dec 22, 2025

ok @polina-c . I rebased on main, got everything building again and replaced "interactionId" with "callId" as well as most of the other suggestions I well.

also, the latest dartantic_ai works with the latest mistral if that's of interest.

@polina-c
Copy link
Collaborator

Amazing! Thank you 🙏

@polina-c polina-c merged commit 3b98cd6 into flutter:main Dec 23, 2025
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create initial package genai_primitives

4 participants