Repository navigation
refactor(ai): make the open-set value types extension types - #42
VelikovPetar wants to merge 2 commits into
Conversation
AIMessagePartKind, AIReasoningStatus, AIToolCallStatus, AIToolExecutor, AIToolApprovalDecision, AIMessageRole and AIMessageAttachmentKind become `extension type const X(String _) implements String`, the pattern the Stream Chat Flutter SDK uses for its open sets. Callers compare or switch on them as strings, with no `.value`. AIMessageRole and AIMessageAttachmentKind gain `values` and `isKnown` like the others. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xsahil03x
left a comment
There was a problem hiding this comment.
Thanks, this is a nice cleanup: the hand-written ==/hashCode/toString boilerplate goes away and the types now line up with AttachmentType in stream_chat. I checked that all seven types are converted the same way, that nothing in lib/, the example, the README or the tests still reaches for .value, that no runtime is checks or mixed-type maps or sets depend on the old class identity, and that the JSON still round-trips as plain strings. dart analyze --fatal-infos, dart format and flutter test --exclude-tags golden (1250 tests) all pass.
Please do these before merging:
- Fix the CHANGELOG entry, which describes a change from a class form that no release ever had (see inline).
The rest is optional and inline.
Merges the two equality tests, which both only exercise String ==. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xsahil03x
left a comment
There was a problem hiding this comment.
Thanks! Each type's Added entry now says what it is, and the tests read well merged. Verified against the new code.
🎯 Goal
The package's open sets — values an agent writes as strings, of which the package knows some but must keep the rest — were immutable classes wrapping a
Stringwith hand-written==,hashCodeandtoString. The Stream Chat Flutter SDK models the same thing as extension types onString(e.g.AttachmentType); this does the same here, so callers compare and switch on them as plain strings.🛠 Implementation details
AIMessagePartKind,AIReasoningStatus,AIToolCallStatus,AIToolExecutor,AIToolApprovalDecision,AIMessageRoleandAIMessageAttachmentKindare nowextension type const X(String _) implements String, each with its constants,valuesandisKnown.AIToolCallStatus.isFinishedstays.AIMessageRoleandAIMessageAttachmentKindgainvaluesandisKnown, like the other five..value: JSON writing,toStrings, the doc samples and the README now use the value itself (switch (part.kind) { 'ai_citation' => … }).`status` "queued" is not one this package knows) instead of printing the oldtoString().AIToolCallStatus.running == AIToolExecutor('running')); the test that asserted otherwise is replaced by ones checking each type equals its raw string.#41 adds
AIToolCallStatus.awaitingAuthorizationto the class form; whichever lands second needs a small rebase inai_tool_call_part.dart.🧪 Testing
dart analyze --fatal-infosanddart formatclean.CI=true flutter teston parts, conversation, components and tools: all pass exceptAIToolApprovalView goldens light/dark (variant: CI), which fail identically onmainon a macOS host (CI goldens are Linux-rendered).🤖 Generated with Claude Code