Skip to content

Initial implementation of prompt builder.#777

Merged
polina-c merged 68 commits intoflutter:mainfrom
polina-c:crud
Mar 4, 2026
Merged

Initial implementation of prompt builder.#777
polina-c merged 68 commits intoflutter:mainfrom
polina-c:crud

Conversation

@polina-c
Copy link
Collaborator

@polina-c polina-c commented Feb 26, 2026

Contributes to #751

gemini-code-assist[bot]

This comment was marked as outdated.

@polina-c polina-c marked this pull request as ready for review March 1, 2026 23:39
@polina-c polina-c requested a review from gspencergoog March 1, 2026 23:39
@polina-c
Copy link
Collaborator Author

polina-c commented Mar 1, 2026

/gemini review

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 significant and valuable refactoring by creating a PromptBuilder to centralize and structure the generation of system prompts. The use of PromptFragments, ProtocolMessages, and SurfaceOperations makes the process more modular, maintainable, and extensible. The changes across the example apps and core library are consistent with this new approach. I've identified a few issues, including a critical syntax error that will prevent compilation, a potential regression, and some opportunities for improving maintainability and test coverage. Please see the detailed comments for specifics.


/// Code execution restriction.
///
/// This is useful when AI may need to execute code.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't seem like an accurate comment.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

replaced with 'This is useful to communicate limitations of code execution to the AI.'

does it look better?


String get tickedName => '`$name`';

static String explainMessages(Set<ProtocolMessages> operations) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should probably be Iterable, not Set. You can call toSet() internally if you want to ensure uniqueness.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is convenient/ergnomic to prepare this parameter as set:

    final operations = <ProtocolMessages>{};
    if (create) {
      operations.addAll([
        ProtocolMessages.createSurface,
        ProtocolMessages.updateComponents,
      ]);
    }
    if (update) {
      operations.add(ProtocolMessages.updateComponents);
    }
    if (delete) {
      operations.add(ProtocolMessages.deleteSurface);
    }
    if (dataModel) {
      operations.add(ProtocolMessages.updateDataModel);
    }

It is extra code and mental effort for reader to convert it back and forth.

Am I missing something?

Copy link
Collaborator

Choose a reason for hiding this comment

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

A Set is an Iterable, so you can still do that. But you can also pass a List (which is also Iterable), and there's no chance that the passed-in operations collection will be accidentally modified inside this function, since iterable can't be modified.

required this.delete,
required this.dataModel,
});
SurfaceOperations.createOnly({required bool dataModel})
Copy link
Collaborator

Choose a reason for hiding this comment

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

This seems overly complicated, and doesn't scale. Imagine adding 10 more message types... Why not just accept an iterable of ProtocolMessages, or even just leave it as the SurfaceOperations constructor above, and just make all the bools default to false?

Copy link
Collaborator Author

@polina-c polina-c Mar 2, 2026

Choose a reason for hiding this comment

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

Yes, it is good idea to have all bools defaulting to false. Added.

If we have 10 operations, we will not create 10^2 constructors.

I believe though having some helper methods will add some convenience, readability and ergonomics.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well, but is SurfaceOperations(update: true) really more ergonomic than SurfaceOperations.updateOnly()? They both are pretty clear, and exactly the same length.

And why isn't it SurfaceOperations.update() if SurfaceOperations.createAndUpdate() exists? Ahh, because then it clashes with the member, I see. But then maybe the other should be SurfaceOperations.createAndUpdateOnly() to be consistent?

What rules will we use to know what messages to include in the "convenience" set? Even adding one more common message to the combinations would double the list (8 instead of 4 combinations), plus having createAndUpdateAndFoobar gets crazy long...


parts.add('''
IMPORTANT:
- Do not use tools or function calls for UI generation. Use JSON text blocks.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This might not be a great piece of advice in all cases. Some implementations might use functions to generate A2UI. For instance, if you had an MCP wrapper around it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

defined TechnicalPossibilities

parts.add('''
IMPORTANT:
- Do not use tools or function calls for UI generation. Use JSON text blocks.
- Ensure all JSON is valid and fenced with ```json ... ```.
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should probably have a better fence than this. Something like:
<a2ui_json>
```json
```
</a2ui_json>

or
-----BEGIN_A2UI_JSON-----
```json
```
-----END_A2UI_JSON-----

There will still be JSON fences around it but we should try and still allow the generation to generate other non-A2UI JSON. Right now that isn't possible.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

-----A2UI_JSON_SCHEMA_START-----
```json
$a2uiSchema

-----A2UI_JSON_SCHEMA_END-------


**OUTPUT FORMAT:**
You must output a VALID JSON object representing one of the A2UI message types ($operationsFormatted).
- Do NOT use function blocks or tool calls for these messages.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Again, not always good advice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

defined TechnicalPossibilities

@polina-c polina-c requested a review from gspencergoog March 3, 2026 23:31
Copy link
Collaborator

@gspencergoog gspencergoog left a comment

Choose a reason for hiding this comment

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

I'm a little concerned that golden files aren't the best way to test this (might be fragile), but we can assess that later and change it if they become annoying.

Co-authored-by: Greg Spencer <gspencergoog@users.noreply.github.com>
@polina-c
Copy link
Collaborator Author

polina-c commented Mar 4, 2026

I'm a little concerned that golden files aren't the best way to test this (might be fragile), but we can assess that later and change it if they become annoying.

Goldens are great, because they are easy to fix, with visibility on PRs about what is changed.

Text goldens are better than picture goldens, because they are not flacky.

But, yes, some extra effort.

Yes, let's see how it goes.

@polina-c polina-c merged commit 1e221d0 into flutter:main Mar 4, 2026
25 checks passed
@polina-c polina-c deleted the crud branch March 4, 2026 22:00
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.

2 participants