genui_gen 0.14.1
genui_gen: ^0.14.1 copied to clipboard
Annotations and runtime helpers to generate genui CatalogItems from your own Flutter widgets. Derive the schema from the constructor so the catalog can never drift.
0.14.1 #
genUiFuzztakeshost, the app each surface is drawn in. It was always a plainMaterialApp, so a catalog whose components read their app's theme failed on every component before any case ran: drawn outside its app, a component that reads aThemeExtensionwith!has nothing to read. Found fuzzing a real app's catalog. Left out,hostis the same plain app as before.
0.14.0 #
- Re-exports
Catalog,CatalogItemandJsonMapalongsideA2uiSchemas,ClientFunctionandClientFunctionReturnType, which were already here. Generated code names those six and nothing else of the renderer, so an annotated file, and the generated catalog, now need only this library. genui is being redesigned asa2ui_flutter; with the renderer behind this one export, moving to it is a change in this package rather than in every app's generated code. If your analyzer now reports an import ofpackage:genui/genui.dartas unnecessary, nothing else in that file used it and it can go. genUiCatalogDiffno longer reports a child property as a breaking type change when one catalog writes"type": "string"and the other points atComponentIdin A2UI'scommon_types.json. That definition is a string and nothing more, and it is howa2ui_flutterdescribes a child. A reference to any other definition still compares by name.
0.13.2 #
- Documentation only. The quickstart asked for
genui_gen: ^0.12.0, which never resolves to 0.13 and leaves out the recorder fix in 0.13.1. It asks for^0.13.1now. - The README links Quincena, a complete app built with this package: an agent composes every answer from twenty generated components and six generated functions, with the inspector, recorded sessions and the test helpers wired in.
0.13.1 #
GenUiTraceRecordercopied nothing when it recorded a message from the agent. The controller can keep anupdateDataModel's value by reference and write into it as the person types, so a recorded message changed after the fact and the trace showed the person's input as if the agent had sent it. It also skippedredact, which only looked at the data model steps. Found by a copied session in an app that redacts the free-text field of a form: the field came out redacted in the data steps and in full in the agent's message. Messages are now copied when they are recorded.redactnow applies to what an agent writes withupdateDataModelas well, including one that writes below the root. A path named there never reaches the file, whoever put the value in it.
0.13.0 #
- Added
package:genui_gen/inspector.dart.GenUiInspectorwraps the app and draws a panel over the running session: the component tree the model built, every data model path with what holds it and what reads it, what a screen reader would announce, and the messages that got the screen into this state. Debugging an ordinary screen starts by opening the file that built it, and a generated screen has no such file. - The Data tab reads bindings both ways, which is where it earns its keep. A path nothing on the surface reads is payload the agent paid for and nobody saw; a path a component binds that the data model has no entry for is the usual reason a field renders empty with no error anywhere.
- Added
GenUiSurfaceGraph, the same reading with no widgets in it, for a test that wants to assert on the shape of a surface. It reports components nothing reaches from the root and components that contain themselves, and is honest about the one thing it cannot know: A2UI names a child with a plain string, so a reference to a component that was never created is indistinguishable from text. GenUiTraceRecordernow implementsA2uiMessageSink, so it drops into anywhere a controller goes, and exposeschangesfor a UI built over a trace that is still growing.- Added
GenUiSemanticNode.isOperable, the rulegenUiSemanticsAuditalready used for "is this a control someone works, or a region they scroll past". The inspector reads the same rule, so an unnamed scrollable is not reported as an unnamed control in one place and ignored in the other.
0.12.0 #
- Added
genUiAsStringMap,genUiAsNumMapandgenUiAsBoolMap, which the generated code calls for aMap<String, V>property. An entry the model got wrong is dropped rather than defaulted: a map is a set of keys the model chose, so a key it could not express is better absent than present and wrong.
0.11.0 #
- Added
genUiFuzz, which renders everything the catalog's own schema allows and reports what broke. A catalog is a contract with something that cannot be recompiled, and the only thing holding a model to it is a JSON schema. Every widget test writes the input the author had in mind; this writes the ones the schema permits and the author did not: a required property left out, a string where a number was declared, a binding that never resolves, a list with two hundred entries. Each finding carries the exact component the renderer was handed, so a case can be pasted into a test rather than reconstructed from a description of it. - The cases come from mutating each item's own generated example rather than
from reading the schema, so a hand-written
CatalogItemis fuzzed as well as a generated one, as long as it carries example data. - Added
genUiFuzzSummary, a table by component for a CI log. - Added
genUiCoverage, which reads a corpus of recorded sessions and says what the agent actually used.genUiCatalogWeightalready said what each component costs; this says which ones earned it. Together they answer the question nothing else does: the example's catalog spends 43% of every request on components its agent has never once composed. It also names the properties never filled and the enum values never chosen. - Better few-shot samples. The example is what the model learns the property
is for, and
42in a price teaches it that prices are round integers. A property whose name the generator recognises now gets a value that reads like one of its kind, and entries of a list vary instead of repeating. Format hints (a URL, a date, a hex colour) still apply to optional properties, because the model cannot guess a shape it has not seen; prose only replaces a placeholder the example was going to carry anyway.
0.10.0 #
- Added
@GenUiChecked, the validation half of an input component. A2UI lets the agent attach rules to a component: aCheckRuleis a condition and the message to show when it fails, and both are required. The rules belong to the agent, because what counts as valid depends on what it is asking for, so a widget only has to be willing to say so. Annotating a parameter adds achecksproperty to the generated schema and hands that parameter the answer: aString?takes the message of the first failing rule, abooltakes whether every rule passes, and aGenUiCheckResulttakes both. - Added
GenUiChecksandGenUiCheckResult, which the generated code builds. Each rule is evaluated on its own rather than combined, which is what keeps the message. genui'schecksToExpressionfolds the conditions into a singleandand drops every message, so the basic catalog can only colour a field red; the sentence the agent wrote for the person reading the screen is the only part of a rule they ever see. - A rule whose condition has not resolved yet counts as passing, so a field is not announced as invalid before the data model arrives. A rule with no message is skipped rather than shown as an unexplained failure, and a condition that throws counts as passing rather than taking the screen down.
- Worth knowing if you compose catalogs:
Catalog.copyWithtakes items and functions separately, and the README used to show onlynewItems. Achecksrule callsrequired,regexoremail, which live in the basic catalog's functions, so merging only the items leaves those rules naming functions nobody registered. The examples now passnewFunctionstoo.
0.9.0 #
- Added
@GenUiFunction, the other half of an A2UI catalog. A catalog holds components, which the agent composes a surface out of, and functions, which it computes a value with through the{"call": ...}form any bound property already accepts. genui ships fourteen of them and an app could add its own only by writing aClientFunctionby hand: the name, the description, anargumentSchemaspelled out in JSON schema, the return type, and anexecutethat digs each argument back out of a map and casts it. That is the same drift this package removes from components, one half of the catalog over. - Added
GenUiClientFunction, which the generated code builds: aClientFunctionwhose body is a callback. Three constructors, for a function that answers immediately, one that answers once later (.async), and one that keeps answering as its own sources change (.streaming). A throw inside the body becomes an error on the stream rather than an exception out of the expression that called it. ClientFunction,ClientFunctionReturnTypeandA2uiSchemasare now re-exported, for the same reasonSis: a file that declares only catalog functions names them in its generated part and should not have to import genui to get them.
0.8.1 #
- Documentation only; no API change.
- Corrected the install instructions. They still listed
json_schema_builderas a direct dependency and imported it in the annotated file, which stopped being true in 0.3.0 when this package began re-exportingS,SchemaandObjectSchemafor exactly that reason. - The README now covers what 0.4 through 0.8 added:
@GenUiWrites, child templates, lists of scalars and enums, and the assembledgenUiCatalogwith itscatalog_id. - Added
homepage, pointing at https://diegolopezrm.github.io/genui_gen/.
0.8.0 #
- Added
genUiTemplateChildrenandgenUiTemplatePath, the runtime half of child templates. A2UI describes the children of a component in two ways: a list of ids the agent wrote out, or{"componentId": "row", "path": "/rows"}repeated once per entry of the data model. The second is what makes a list that grows when the agent sends data rather than a new surface, and a generated widget could not accept it. - Each template child reads its own entry: the child of
/rowsat index 2 bindstitleagainst/rows/2/title, so one component describes every row. Children are keyed by entry rather than by position, so a row removed from the middle takes its state with it instead of handing it to the row below. - Added
GenUiBinding.valueandGenUiValues.raw, which resolve a path and hand back what it holds without coercing it. The typed bindings are right for a widget property; a template needs the list or the map itself.
0.7.0 #
-
Added
package:genui_gen/tracing.dart: record an agent session and replay it. A generative interface has a problem an ordinary app does not — the screen that failed is not in the source, because a model composed it once from a context that will not come back — and a trace is that session, kept.GenUiTraceRecorder.attachkeeps every message the agent sent, the contents of each surface's data model whenever they changed, and every action the app sent back;GenUiTracePlayerreplays it with no model and no network, andGenUiTraceViewshows it, at any step.final player = GenUiTracePlayer(trace, catalog: genUiCatalog)..seek(7); await tester.pumpWidget(MaterialApp(home: GenUiTraceView(player: player)));Because the replay renders against the app's current catalog, an old session is also a regression test: a catalog change that breaks a real conversation fails before a user finds it.
-
redactnames the data model paths a recording must not keep. A session records what the user typed, so the field holding an email has to be named before the first recording rather than after the first leak. -
Added
genUiCatalogDiff, which reports what changed between two catalog documents from where it matters: the model. A removed component, a new required property, a dropped enum value and a changed type are breaking, because the agent's prompt still describes the old one. A new optional property and a new enum value are not. -
Added
genUiSemanticsAudit, which reads the recording the golden test already keeps and reports what a screen reader user could not work with: a control with nothing to announce, a component that reaches assistive technology as nothing at all, two controls that announce themselves identically. -
Added
genUiCatalogWeight, which says how much of every prompt each component takes up. A catalog is sent on every request and nothing makes its cost visible. -
GenUiSemanticNodenow recordstooltipalongsidename. A control named only by a tooltip is not unnamed, but it is not named the same way either, and the recording shows which of the two it has. -
The example app records a session with its own widgets, checks its catalog against the published one, and lists what the basic catalog gives a screen reader today: an audio player whose play button and two sliders announce nothing, an image that exposes nothing at all, and a slider with a
labelthe catalog never passes on.
0.6.0 #
-
Added
package:genui_gen/testing.dart, which checks the half of a catalog the schema cannot: what a generated component actually exposes to the person using it.genUiSemanticsreads the role, name, value, state and actions of a rendered surface, in traversal order;genUiSemanticsGoldenrecords that into a JSON file and fails when it changes;GenUiExampleSurfacerenders one item's generated example through a realSurfaceController, so the test covers the whole path — schema, bindings and actions — rather than the widget alone.expect( genUiSemanticsGolden(recorded, File('test/genui_semantics.json')), isNull, ); -
The recorded file is checked in and read in review. It is the answer to "what can the model make this app announce, press or report", which is the part of a change that a Dart diff does not show. Re-record a deliberate change with
GENUI_UPDATE_GOLDENS=1. -
The file is written in the shape A2UI's rendering cases use — role, name, value, state, actions — so the same recording describes the catalog to a renderer on another platform.
-
example/test/genui_semantics.jsonrecords the example app's catalog, andexample/test/genui_semantics_test.dartis the test to copy. -
a2ui_coreis now a dependency:GenUiExampleSurfacebuilds the surface from the same message types genui takes.
0.5.0 #
-
Added
genUiCatalogJsonandgenUiCatalogJsonString, which turn aCataloginto the A2UIcatalog.jsondocument that describes it. Inside the app genui puts the catalog in the prompt for you; everything outside this Flutter process needs it as a document — an agent written in Python, a second client rendering the same surfaces in SwiftUI, a review that has to answer what the model was allowed to ask for last Tuesday. The result is the shape A2UI publishes for its own basic catalog:catalogId,components,functionswhen the catalog has any, and the$defsa renderer resolves a component against.final json = genUiCatalogJsonString(genUiCatalog, title: 'Acme catalog'); -
The export takes a
titleand adescriptionof its own. genui fills inA2UI CatalogandCustom catalog of A2UI components and functions.for every catalog ever generated, and an agent handed three of them has nothing else to tell them apart by. -
A catalog with no
catalogIdis rejected rather than exported. A surface names the catalog it was built against, so a document without an id describes components that nothing can ask for. -
example/catalog.jsonis generated from a test, and the README shows the pattern: write the file under--update-goldensand compare against it otherwise, so the document in the repository cannot fall behind the widgets and a reviewer sees what a new@GenUiWidgetexposed to the model.
0.4.0 #
- Added
@GenUiWrites, which makes a control the user operates annotatable. Avoid Function(T)parameter marked@GenUiWrites('<property>')receives a callback that writes the user's value into the surface's data model, at the path the model bound<property>to. It is what genui's ownTextField,Slider,CheckBox,ChoicePicker,DateTimeInputandTabsalready do, and until now an annotated widget had no way to express it: a property was read-only, so a switch or a text field could not be annotated at all.Tmay be aString, anint, adouble, anum, aboolor an enum. - A property some callback writes to is now read back through the same path it
is written to, so the control reflects what the user just did. A literal the
model sent is still honoured until that path holds something, the way
TextFieldseeds itself from its initial value. When the model sends a literal rather than a binding there is no path it named, so the value is written to<componentId>.<property>— the fallback the core catalog uses — and the control stays interactive. - The description of a written property gains a sentence saying so. The callback itself is not in the schema, because the model never supplies it, so the model would otherwise have no way to know that binding the property to a path is how it reads the answer.
- Added the runtime helpers
genUiValueWriter,genUiWritePathandgenUiWriteReference, called by generated code. A write the data model refuses — a non-numeric segment on a list, an index out of bounds — is reported throughctx.reportErrorrather than thrown out of a gesture handler, exactly as a failed action is. - The callback's argument may not be nullable. A2UI has no agreed meaning for
writing
nullto a path, soValueChanged<String?>is a build error rather than a silent choice between "clear it" and "store null". - Additive release: a widget that uses only 0.3 types generates identical code.
0.3.0 #
- Added lists of scalars: a
@GenUiWidgetparameter or@GenUiDatafield may now be aList<int>,List<double>,List<num>, or aList<E>for an enumE. Each was a build error in 0.2. - Added
GenUiBinding.numberListandGenUiValues.numberList, resolved through genui'sBoundList. Entries that are not numbers are dropped, and a numeric string is parsed, the way the core catalog's number binding does. - Added the coercion helper
genUiAsNumList, used by generated decoders for numeric list fields of a@GenUiDataclass. - A list of enums is carried as strings and mapped back by name. A name the enum does not declare is dropped rather than defaulted: the list is the model's, and one bad entry should not silently become a value the author never wrote.
- Re-exported
S,SchemaandObjectSchemafromjson_schema_builder, so an annotated file importsgenui_genalone andjson_schema_builderstops being a direct dependency of consumers.shown rather than exported wholesale; ifScollides with another one-letter name, import withhide S. json_schema_buildermoved from dev_dependencies to dependencies, since those three names are now part of this package's public API.- Additive release: widgets that only use 0.2 types generate identical code.
0.2.0 #
- Added
@GenUiData, marking a plain Dart class as a data shape an annotated widget may receive. A@GenUiWidgetparameter may now be a data class, or aListof one, so widgets that take rows, points or items are annotatable. - Added the
GenUiDecoder<T>typedef used by generated code to rebuild a data class from the map the model produced. - Added
GenUiBinding.objectandGenUiBinding.objectList, resolved through genui'sBoundObjectandBoundList, plus the matchingGenUiValues.objectandGenUiValues.objectListaccessors.objectListskips entries that are not maps instead of throwing. - Added the coercion helpers
genUiAsString,genUiAsNum,genUiAsBool,genUiAsStringList,genUiAsObjectandgenUiAsObjectList. Generated decoders call them instead of casting, so a field of the wrong type degrades the way genui'sBound*widgets degrade instead of throwing aTypeErrorinsidebuild. - Added
GenUiMissingFieldReporter,genUiMissingFieldandgenUiNestedField, which carry the missing-property report into a data object: a required field the model left out of a row reaches the model asrows.label. - Additive release: widgets that only use 0.1 types generate identical code.
0.1.2 #
- Version bump to stay aligned with
genui_gen_builder0.1.2. No API changes.