@genesislcap/ai-assistant 15.86.0 → 15.86.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/ai-assistant.api.json +63 -2
  2. package/dist/ai-assistant.d.ts +10 -0
  3. package/dist/custom-elements.json +795 -724
  4. package/dist/dts/components/chat-bubble/chat-bubble.d.ts +9 -2
  5. package/dist/dts/components/chat-bubble/chat-bubble.d.ts.map +1 -1
  6. package/dist/dts/components/chat-markdown/chat-markdown.d.ts.map +1 -1
  7. package/dist/dts/genesis/write-review/write-review.d.ts +23 -0
  8. package/dist/dts/genesis/write-review/write-review.d.ts.map +1 -1
  9. package/dist/dts/genesis/write-review/write-review.styles.d.ts.map +1 -1
  10. package/dist/dts/genesis/write-review/write-review.template.d.ts.map +1 -1
  11. package/dist/dts/main/main.d.ts +8 -0
  12. package/dist/dts/main/main.d.ts.map +1 -1
  13. package/dist/dts/main/main.styles.d.ts.map +1 -1
  14. package/dist/dts/main/main.template.d.ts.map +1 -1
  15. package/dist/dts/main/main.types.d.ts +2 -0
  16. package/dist/dts/main/main.types.d.ts.map +1 -1
  17. package/dist/dts/react.d.ts +1 -0
  18. package/dist/esm/components/chat-bubble/chat-bubble.js +18 -21
  19. package/dist/esm/components/chat-markdown/chat-markdown.js +18 -2
  20. package/dist/esm/genesis/write-review/write-review.js +48 -0
  21. package/dist/esm/genesis/write-review/write-review.styles.js +67 -1
  22. package/dist/esm/genesis/write-review/write-review.template.js +44 -27
  23. package/dist/esm/main/main.js +13 -0
  24. package/dist/esm/main/main.styles.js +42 -0
  25. package/dist/esm/main/main.template.js +11 -1
  26. package/dist/esm/main/main.types.js +2 -0
  27. package/dist/react.cjs +6 -1
  28. package/dist/react.mjs +6 -1
  29. package/docs/styling.md +10 -4
  30. package/package.json +17 -17
@@ -1408,6 +1408,287 @@
1408
1408
  }
1409
1409
  ]
1410
1410
  },
1411
+ {
1412
+ "kind": "javascript-module",
1413
+ "path": "src/channel/ai-activity-bus.ts",
1414
+ "declarations": [
1415
+ {
1416
+ "kind": "variable",
1417
+ "name": "NOOP_ACTIVITY_BUS",
1418
+ "type": {
1419
+ "text": "ActivityBus"
1420
+ },
1421
+ "default": "{ publish: () => {} }",
1422
+ "description": "No-op ActivityBus. The default when no bus is injected (Node, tests, headless\nserver use) — publishing goes nowhere and nothing is left open to tear down."
1423
+ },
1424
+ {
1425
+ "kind": "class",
1426
+ "description": "Typed in-process event bus for AI assistant activity events.\n\nDispatches events synchronously to all local subscribers in the same JS module instance\n(i.e. the same browser tab). Events listed in `crossTabEvents` are additionally forwarded\nvia a shared `BroadcastChannel` so that other tabs on the same origin receive them.",
1427
+ "name": "AgenticActivityBus",
1428
+ "members": [
1429
+ {
1430
+ "kind": "field",
1431
+ "name": "subscribers",
1432
+ "privacy": "private",
1433
+ "readonly": true,
1434
+ "default": "new Map<string, Set<AnyHandler>>()"
1435
+ },
1436
+ {
1437
+ "kind": "field",
1438
+ "name": "crossTabEvents",
1439
+ "type": {
1440
+ "text": "Set<string>"
1441
+ },
1442
+ "privacy": "private",
1443
+ "readonly": true,
1444
+ "default": "new Set(config?.crossTabEvents ?? [])"
1445
+ },
1446
+ {
1447
+ "kind": "field",
1448
+ "name": "channelNameFactory",
1449
+ "type": {
1450
+ "text": "() => string | undefined"
1451
+ },
1452
+ "privacy": "private",
1453
+ "readonly": true
1454
+ },
1455
+ {
1456
+ "kind": "field",
1457
+ "name": "channel",
1458
+ "type": {
1459
+ "text": "BroadcastChannel | undefined"
1460
+ },
1461
+ "privacy": "private"
1462
+ },
1463
+ {
1464
+ "kind": "field",
1465
+ "name": "channelInitialised",
1466
+ "type": {
1467
+ "text": "boolean"
1468
+ },
1469
+ "privacy": "private",
1470
+ "default": "false"
1471
+ },
1472
+ {
1473
+ "kind": "method",
1474
+ "name": "ensureChannel",
1475
+ "privacy": "private",
1476
+ "return": {
1477
+ "type": {
1478
+ "text": "void"
1479
+ }
1480
+ },
1481
+ "description": "Lazily open the cross-tab `BroadcastChannel` on first use. Deferred (rather than\ncreated in the constructor) so that importing this module, or constructing the bus\noff-browser (Node, tests, headless server), never opens a live channel or reads\n`sessionStorage` — both would keep a Node event loop alive and hang the process.\nCross-tab forwarding is inherently browser-only, so channel creation is gated on a\nbrowser environment; elsewhere the bus stays purely in-process."
1482
+ },
1483
+ {
1484
+ "kind": "method",
1485
+ "name": "subscribe",
1486
+ "return": {
1487
+ "type": {
1488
+ "text": "() => void"
1489
+ }
1490
+ },
1491
+ "parameters": [
1492
+ {
1493
+ "name": "type",
1494
+ "type": {
1495
+ "text": "K"
1496
+ }
1497
+ },
1498
+ {
1499
+ "name": "handler",
1500
+ "type": {
1501
+ "text": "(detail: AgenticActivityEvents[K]) => void"
1502
+ }
1503
+ }
1504
+ ],
1505
+ "description": "Subscribe to an event. Returns an unsubscribe function — call it in\n`disconnectedCallback` to avoid memory leaks."
1506
+ },
1507
+ {
1508
+ "kind": "method",
1509
+ "name": "publish",
1510
+ "return": {
1511
+ "type": {
1512
+ "text": "void"
1513
+ }
1514
+ },
1515
+ "parameters": [
1516
+ {
1517
+ "name": "type",
1518
+ "type": {
1519
+ "text": "K"
1520
+ }
1521
+ },
1522
+ {
1523
+ "name": "detail",
1524
+ "type": {
1525
+ "text": "AgenticActivityEvents[K]"
1526
+ }
1527
+ }
1528
+ ],
1529
+ "description": "Publish an event to all local subscribers and, if configured, to other tabs\nvia BroadcastChannel."
1530
+ },
1531
+ {
1532
+ "kind": "method",
1533
+ "name": "addCrossTabEvent",
1534
+ "return": {
1535
+ "type": {
1536
+ "text": "void"
1537
+ }
1538
+ },
1539
+ "parameters": [
1540
+ {
1541
+ "name": "type",
1542
+ "type": {
1543
+ "text": "keyof AgenticActivityEvents"
1544
+ }
1545
+ }
1546
+ ],
1547
+ "description": "Add an event type to the cross-tab forwarding set at runtime.\nMust be called before the first AgenticActivityBus.publish of that event type."
1548
+ },
1549
+ {
1550
+ "kind": "method",
1551
+ "name": "close",
1552
+ "return": {
1553
+ "type": {
1554
+ "text": "void"
1555
+ }
1556
+ },
1557
+ "description": "Close the underlying BroadcastChannel. Call once on application teardown if needed."
1558
+ },
1559
+ {
1560
+ "kind": "method",
1561
+ "name": "notifyLocal",
1562
+ "privacy": "private",
1563
+ "return": {
1564
+ "type": {
1565
+ "text": "void"
1566
+ }
1567
+ },
1568
+ "parameters": [
1569
+ {
1570
+ "name": "type",
1571
+ "type": {
1572
+ "text": "string"
1573
+ }
1574
+ },
1575
+ {
1576
+ "name": "detail",
1577
+ "type": {
1578
+ "text": "unknown"
1579
+ }
1580
+ }
1581
+ ]
1582
+ }
1583
+ ]
1584
+ },
1585
+ {
1586
+ "kind": "variable",
1587
+ "name": "agenticActivityBus",
1588
+ "default": "new AgenticActivityBus({\n crossTabEvents: ['halo-start', 'halo-stop', 'tool-loop-start', 'tool-loop-end'],\n // Lazy: the tab-scoped name (and its `sessionStorage` read) is computed on first\n // cross-tab use in a browser, not at module-eval — so importing this module is\n // side-effect-free and Node/test-safe.\n channelNameFactory: () => getTabScopedChannelName('foundation-ai-activity'),\n})",
1589
+ "description": "Pre-instantiated singleton event bus for AI assistant activity.\n\n- `halo-start` / `halo-stop` are forwarded via a tab-scoped `BroadcastChannel` so that\n popout windows opened from this tab show halo animations, while remaining isolated from\n unrelated tabs on the same origin (tab-scoped channel name).\n- `tool-loop-start` / `tool-loop-end` are cross-tab for the same reason: they describe the\n assistant's lifecycle (a turn beginning / ending), and the most common subscribers\n (workspace transitions, post-turn deferred recomputation, UI gates tied to the assistant\n being idle) need the event regardless of whether the user is interacting with the chat\n in the main tab or a popout window. Tab-local-only telemetry can subscribe and filter.\n- `chat-popout` / `chat-popin` are in-memory only — they must only affect the tab where the\n user clicked."
1590
+ }
1591
+ ],
1592
+ "exports": [
1593
+ {
1594
+ "kind": "js",
1595
+ "name": "NOOP_ACTIVITY_BUS",
1596
+ "declaration": {
1597
+ "name": "NOOP_ACTIVITY_BUS",
1598
+ "module": "src/channel/ai-activity-bus.ts"
1599
+ }
1600
+ },
1601
+ {
1602
+ "kind": "js",
1603
+ "name": "AgenticActivityBus",
1604
+ "declaration": {
1605
+ "name": "AgenticActivityBus",
1606
+ "module": "src/channel/ai-activity-bus.ts"
1607
+ }
1608
+ },
1609
+ {
1610
+ "kind": "js",
1611
+ "name": "agenticActivityBus",
1612
+ "declaration": {
1613
+ "name": "agenticActivityBus",
1614
+ "module": "src/channel/ai-activity-bus.ts"
1615
+ }
1616
+ }
1617
+ ]
1618
+ },
1619
+ {
1620
+ "kind": "javascript-module",
1621
+ "path": "src/channel/ai-activity-channel.ts",
1622
+ "declarations": [],
1623
+ "exports": []
1624
+ },
1625
+ {
1626
+ "kind": "javascript-module",
1627
+ "path": "src/channel/autopilot-needs-user.ts",
1628
+ "declarations": [
1629
+ {
1630
+ "kind": "function",
1631
+ "name": "setAutopilotNeedsUser",
1632
+ "return": {
1633
+ "type": {
1634
+ "text": "void"
1635
+ }
1636
+ },
1637
+ "parameters": [
1638
+ {
1639
+ "name": "sessionKey",
1640
+ "type": {
1641
+ "text": "string"
1642
+ }
1643
+ },
1644
+ {
1645
+ "name": "needsUser",
1646
+ "type": {
1647
+ "text": "boolean"
1648
+ }
1649
+ }
1650
+ ],
1651
+ "description": "Set it for one session, announcing `autopilot-needs-user` when it changes."
1652
+ },
1653
+ {
1654
+ "kind": "function",
1655
+ "name": "autopilotNeedsUser",
1656
+ "return": {
1657
+ "type": {
1658
+ "text": "boolean"
1659
+ }
1660
+ },
1661
+ "parameters": [
1662
+ {
1663
+ "name": "sessionKey",
1664
+ "optional": true,
1665
+ "type": {
1666
+ "text": "string"
1667
+ }
1668
+ }
1669
+ ],
1670
+ "description": "Whether a session has something waiting on the person — or, without a key (a bubble that cannot\ntell which assistant it holds), whether any session has."
1671
+ }
1672
+ ],
1673
+ "exports": [
1674
+ {
1675
+ "kind": "js",
1676
+ "name": "setAutopilotNeedsUser",
1677
+ "declaration": {
1678
+ "name": "setAutopilotNeedsUser",
1679
+ "module": "src/channel/autopilot-needs-user.ts"
1680
+ }
1681
+ },
1682
+ {
1683
+ "kind": "js",
1684
+ "name": "autopilotNeedsUser",
1685
+ "declaration": {
1686
+ "name": "autopilotNeedsUser",
1687
+ "module": "src/channel/autopilot-needs-user.ts"
1688
+ }
1689
+ }
1690
+ ]
1691
+ },
1411
1692
  {
1412
1693
  "kind": "javascript-module",
1413
1694
  "path": "src/autopilot/autopilot-driver.ts",
@@ -4730,275 +5011,122 @@
4730
5011
  },
4731
5012
  {
4732
5013
  "kind": "js",
4733
- "name": "AutopilotHandBack",
4734
- "declaration": {
4735
- "name": "AutopilotHandBack",
4736
- "module": "./hand-back/hand-back"
4737
- }
4738
- }
4739
- ]
4740
- },
4741
- {
4742
- "kind": "javascript-module",
4743
- "path": "src/autopilot/widget-tools.ts",
4744
- "declarations": [
4745
- {
4746
- "kind": "function",
4747
- "name": "widgetTools",
4748
- "return": {
4749
- "type": {
4750
- "text": "WidgetTools"
4751
- }
4752
- },
4753
- "parameters": [
4754
- {
4755
- "name": "componentName",
4756
- "type": {
4757
- "text": "string"
4758
- }
4759
- },
4760
- {
4761
- "name": "tools",
4762
- "type": {
4763
- "text": "{ [K in keyof TArgs]: WidgetToolSpec<TController, TArgs[K]> }"
4764
- }
4765
- }
4766
- ],
4767
- "description": "Declare tools that read from one widget type (GENC-1660): parameterised reads that a view cannot\nexpress, such as one table's rows, or a page of them.\n\nPut them on the autopilot (`defineAutopilot({ widgetTools: [...] })`), never discovered from the\nregistration. Its tool list is fixed when its session starts, sorted by name, and identical for\nevery decision, so the cache never breaks. Each call is routed to the interaction of\n`componentName` the autopilot is deciding, and `run` gets its controller; with none open, it is\nrefused with a reason. While one is open, the autopilot's tail says which tools are usable now.\n\nReads only. Their results leave the autopilot's history at the end of the decision, as\n`widget_read`'s do."
4768
- }
4769
- ],
4770
- "exports": [
4771
- {
4772
- "kind": "js",
4773
- "name": "widgetTools",
4774
- "declaration": {
4775
- "name": "widgetTools",
4776
- "module": "src/autopilot/widget-tools.ts"
4777
- }
4778
- }
4779
- ]
4780
- },
4781
- {
4782
- "kind": "javascript-module",
4783
- "path": "src/channel/ai-activity-bus.ts",
4784
- "declarations": [
4785
- {
4786
- "kind": "variable",
4787
- "name": "NOOP_ACTIVITY_BUS",
4788
- "type": {
4789
- "text": "ActivityBus"
4790
- },
4791
- "default": "{ publish: () => {} }",
4792
- "description": "No-op ActivityBus. The default when no bus is injected (Node, tests, headless\nserver use) — publishing goes nowhere and nothing is left open to tear down."
4793
- },
4794
- {
4795
- "kind": "class",
4796
- "description": "Typed in-process event bus for AI assistant activity events.\n\nDispatches events synchronously to all local subscribers in the same JS module instance\n(i.e. the same browser tab). Events listed in `crossTabEvents` are additionally forwarded\nvia a shared `BroadcastChannel` so that other tabs on the same origin receive them.",
4797
- "name": "AgenticActivityBus",
4798
- "members": [
4799
- {
4800
- "kind": "field",
4801
- "name": "subscribers",
4802
- "privacy": "private",
4803
- "readonly": true,
4804
- "default": "new Map<string, Set<AnyHandler>>()"
4805
- },
4806
- {
4807
- "kind": "field",
4808
- "name": "crossTabEvents",
4809
- "type": {
4810
- "text": "Set<string>"
4811
- },
4812
- "privacy": "private",
4813
- "readonly": true,
4814
- "default": "new Set(config?.crossTabEvents ?? [])"
4815
- },
4816
- {
4817
- "kind": "field",
4818
- "name": "channelNameFactory",
4819
- "type": {
4820
- "text": "() => string | undefined"
4821
- },
4822
- "privacy": "private",
4823
- "readonly": true
4824
- },
4825
- {
4826
- "kind": "field",
4827
- "name": "channel",
4828
- "type": {
4829
- "text": "BroadcastChannel | undefined"
4830
- },
4831
- "privacy": "private"
4832
- },
4833
- {
4834
- "kind": "field",
4835
- "name": "channelInitialised",
4836
- "type": {
4837
- "text": "boolean"
4838
- },
4839
- "privacy": "private",
4840
- "default": "false"
4841
- },
4842
- {
4843
- "kind": "method",
4844
- "name": "ensureChannel",
4845
- "privacy": "private",
4846
- "return": {
4847
- "type": {
4848
- "text": "void"
4849
- }
4850
- },
4851
- "description": "Lazily open the cross-tab `BroadcastChannel` on first use. Deferred (rather than\ncreated in the constructor) so that importing this module, or constructing the bus\noff-browser (Node, tests, headless server), never opens a live channel or reads\n`sessionStorage` — both would keep a Node event loop alive and hang the process.\nCross-tab forwarding is inherently browser-only, so channel creation is gated on a\nbrowser environment; elsewhere the bus stays purely in-process."
4852
- },
4853
- {
4854
- "kind": "method",
4855
- "name": "subscribe",
4856
- "return": {
4857
- "type": {
4858
- "text": "() => void"
4859
- }
4860
- },
4861
- "parameters": [
4862
- {
4863
- "name": "type",
4864
- "type": {
4865
- "text": "K"
4866
- }
4867
- },
4868
- {
4869
- "name": "handler",
4870
- "type": {
4871
- "text": "(detail: AgenticActivityEvents[K]) => void"
4872
- }
4873
- }
4874
- ],
4875
- "description": "Subscribe to an event. Returns an unsubscribe function — call it in\n`disconnectedCallback` to avoid memory leaks."
4876
- },
4877
- {
4878
- "kind": "method",
4879
- "name": "publish",
4880
- "return": {
4881
- "type": {
4882
- "text": "void"
4883
- }
4884
- },
4885
- "parameters": [
4886
- {
4887
- "name": "type",
4888
- "type": {
4889
- "text": "K"
4890
- }
4891
- },
4892
- {
4893
- "name": "detail",
4894
- "type": {
4895
- "text": "AgenticActivityEvents[K]"
4896
- }
4897
- }
4898
- ],
4899
- "description": "Publish an event to all local subscribers and, if configured, to other tabs\nvia BroadcastChannel."
4900
- },
4901
- {
4902
- "kind": "method",
4903
- "name": "addCrossTabEvent",
4904
- "return": {
4905
- "type": {
4906
- "text": "void"
4907
- }
4908
- },
4909
- "parameters": [
4910
- {
4911
- "name": "type",
4912
- "type": {
4913
- "text": "keyof AgenticActivityEvents"
4914
- }
4915
- }
4916
- ],
4917
- "description": "Add an event type to the cross-tab forwarding set at runtime.\nMust be called before the first AgenticActivityBus.publish of that event type."
4918
- },
5014
+ "name": "AutopilotHandBack",
5015
+ "declaration": {
5016
+ "name": "AutopilotHandBack",
5017
+ "module": "./hand-back/hand-back"
5018
+ }
5019
+ }
5020
+ ]
5021
+ },
5022
+ {
5023
+ "kind": "javascript-module",
5024
+ "path": "src/autopilot/widget-tools.ts",
5025
+ "declarations": [
5026
+ {
5027
+ "kind": "function",
5028
+ "name": "widgetTools",
5029
+ "return": {
5030
+ "type": {
5031
+ "text": "WidgetTools"
5032
+ }
5033
+ },
5034
+ "parameters": [
4919
5035
  {
4920
- "kind": "method",
4921
- "name": "close",
4922
- "return": {
4923
- "type": {
4924
- "text": "void"
4925
- }
4926
- },
4927
- "description": "Close the underlying BroadcastChannel. Call once on application teardown if needed."
5036
+ "name": "componentName",
5037
+ "type": {
5038
+ "text": "string"
5039
+ }
4928
5040
  },
4929
5041
  {
4930
- "kind": "method",
4931
- "name": "notifyLocal",
4932
- "privacy": "private",
4933
- "return": {
4934
- "type": {
4935
- "text": "void"
4936
- }
4937
- },
4938
- "parameters": [
4939
- {
4940
- "name": "type",
4941
- "type": {
4942
- "text": "string"
4943
- }
4944
- },
4945
- {
4946
- "name": "detail",
4947
- "type": {
4948
- "text": "unknown"
4949
- }
4950
- }
4951
- ]
5042
+ "name": "tools",
5043
+ "type": {
5044
+ "text": "{ [K in keyof TArgs]: WidgetToolSpec<TController, TArgs[K]> }"
5045
+ }
4952
5046
  }
4953
- ]
4954
- },
5047
+ ],
5048
+ "description": "Declare tools that read from one widget type (GENC-1660): parameterised reads that a view cannot\nexpress, such as one table's rows, or a page of them.\n\nPut them on the autopilot (`defineAutopilot({ widgetTools: [...] })`), never discovered from the\nregistration. Its tool list is fixed when its session starts, sorted by name, and identical for\nevery decision, so the cache never breaks. Each call is routed to the interaction of\n`componentName` the autopilot is deciding, and `run` gets its controller; with none open, it is\nrefused with a reason. While one is open, the autopilot's tail says which tools are usable now.\n\nReads only. Their results leave the autopilot's history at the end of the decision, as\n`widget_read`'s do."
5049
+ }
5050
+ ],
5051
+ "exports": [
4955
5052
  {
4956
- "kind": "variable",
4957
- "name": "agenticActivityBus",
4958
- "default": "new AgenticActivityBus({\n crossTabEvents: ['halo-start', 'halo-stop', 'tool-loop-start', 'tool-loop-end'],\n // Lazy: the tab-scoped name (and its `sessionStorage` read) is computed on first\n // cross-tab use in a browser, not at module-eval — so importing this module is\n // side-effect-free and Node/test-safe.\n channelNameFactory: () => getTabScopedChannelName('foundation-ai-activity'),\n})",
4959
- "description": "Pre-instantiated singleton event bus for AI assistant activity.\n\n- `halo-start` / `halo-stop` are forwarded via a tab-scoped `BroadcastChannel` so that\n popout windows opened from this tab show halo animations, while remaining isolated from\n unrelated tabs on the same origin (tab-scoped channel name).\n- `tool-loop-start` / `tool-loop-end` are cross-tab for the same reason: they describe the\n assistant's lifecycle (a turn beginning / ending), and the most common subscribers\n (workspace transitions, post-turn deferred recomputation, UI gates tied to the assistant\n being idle) need the event regardless of whether the user is interacting with the chat\n in the main tab or a popout window. Tab-local-only telemetry can subscribe and filter.\n- `chat-popout` / `chat-popin` are in-memory only — they must only affect the tab where the\n user clicked."
5053
+ "kind": "js",
5054
+ "name": "widgetTools",
5055
+ "declaration": {
5056
+ "name": "widgetTools",
5057
+ "module": "src/autopilot/widget-tools.ts"
5058
+ }
5059
+ }
5060
+ ]
5061
+ },
5062
+ {
5063
+ "kind": "javascript-module",
5064
+ "path": "src/config/config.ts",
5065
+ "declarations": [
5066
+ {
5067
+ "kind": "function",
5068
+ "name": "defineAgent",
5069
+ "description": "Identity helper that infers the narrowest possible type for an agent config,\npreserving string literal types (including `name`) without requiring `as const`.\n\nUse this when you need `typeof myAgent` to carry the literal `name` type —\nfor example, when wiring `ChatToolHandlers<typeof myAgent>`.\n\n```ts\nconst myAgent = defineAgent({ name: 'my_agent', ... });\ntype Handlers = ChatToolHandlers<typeof myAgent>;\n// requestSubAgent name param is now typed as 'my_agent'\n```"
4960
5070
  }
4961
5071
  ],
4962
5072
  "exports": [
4963
5073
  {
4964
5074
  "kind": "js",
4965
- "name": "NOOP_ACTIVITY_BUS",
5075
+ "name": "CachePolicy",
4966
5076
  "declaration": {
4967
- "name": "NOOP_ACTIVITY_BUS",
4968
- "module": "src/channel/ai-activity-bus.ts"
5077
+ "name": "CachePolicy",
5078
+ "module": "src/config/config.ts"
4969
5079
  }
4970
5080
  },
4971
5081
  {
4972
5082
  "kind": "js",
4973
- "name": "AgenticActivityBus",
5083
+ "name": "ChatFallback",
4974
5084
  "declaration": {
4975
- "name": "AgenticActivityBus",
4976
- "module": "src/channel/ai-activity-bus.ts"
5085
+ "name": "ChatFallback",
5086
+ "module": "src/config/config.ts"
4977
5087
  }
4978
5088
  },
4979
5089
  {
4980
5090
  "kind": "js",
4981
- "name": "agenticActivityBus",
5091
+ "name": "ChatInputDuringExecutionMode",
4982
5092
  "declaration": {
4983
- "name": "agenticActivityBus",
4984
- "module": "src/channel/ai-activity-bus.ts"
5093
+ "name": "ChatInputDuringExecutionMode",
5094
+ "module": "src/config/config.ts"
5095
+ }
5096
+ },
5097
+ {
5098
+ "kind": "js",
5099
+ "name": "ChatThinkingPolicy",
5100
+ "declaration": {
5101
+ "name": "ChatThinkingPolicy",
5102
+ "module": "src/config/config.ts"
5103
+ }
5104
+ },
5105
+ {
5106
+ "kind": "js",
5107
+ "name": "ChatToolChoice",
5108
+ "declaration": {
5109
+ "name": "ChatToolChoice",
5110
+ "module": "src/config/config.ts"
5111
+ }
5112
+ },
5113
+ {
5114
+ "kind": "js",
5115
+ "name": "defineAgent",
5116
+ "declaration": {
5117
+ "name": "defineAgent",
5118
+ "module": "src/config/config.ts"
4985
5119
  }
4986
5120
  }
4987
5121
  ]
4988
5122
  },
4989
5123
  {
4990
5124
  "kind": "javascript-module",
4991
- "path": "src/channel/ai-activity-channel.ts",
4992
- "declarations": [],
4993
- "exports": []
4994
- },
4995
- {
4996
- "kind": "javascript-module",
4997
- "path": "src/channel/autopilot-needs-user.ts",
5125
+ "path": "src/config/define-stateful-agent.ts",
4998
5126
  "declarations": [
4999
5127
  {
5000
5128
  "kind": "function",
5001
- "name": "setAutopilotNeedsUser",
5129
+ "name": "restoreMachine",
5002
5130
  "return": {
5003
5131
  "type": {
5004
5132
  "text": "void"
@@ -5006,59 +5134,162 @@
5006
5134
  },
5007
5135
  "parameters": [
5008
5136
  {
5009
- "name": "sessionKey",
5137
+ "name": "machine",
5010
5138
  "type": {
5011
- "text": "string"
5012
- }
5139
+ "text": "{ stop: () => void; start: (options?: { state?: unknown }) => void }"
5140
+ },
5141
+ "description": "the machine to restore (already constructed/started)."
5013
5142
  },
5014
5143
  {
5015
- "name": "needsUser",
5144
+ "name": "restored",
5016
5145
  "type": {
5017
- "text": "boolean"
5146
+ "text": "unknown"
5147
+ },
5148
+ "description": "the agent's serialized image (`ctx.restored` in `init`)."
5149
+ },
5150
+ {
5151
+ "name": "key",
5152
+ "default": "'machine'",
5153
+ "description": "the property the machine occupies in the snapshot; defaults to\n`'machine'` to match the conventional `{ machine }` state bag."
5154
+ }
5155
+ ],
5156
+ "description": "Restore a foundation-state-machine instance from a snapshot produced by the\ndefault serializer (or `machine.getPersistedSnapshot()`). Call inside a\nstateful agent's `init` to resume the machine in its exact prior place:\n\n```ts\ninit: ({ restored }) => {\n const machine = new MyMachine();\n restoreMachine(machine, restored); // resume, or no-op on a fresh start\n return { machine };\n}\n```\n\nNo-ops when there is nothing to restore (a fresh session), leaving the\nfreshly-constructed machine in its initial state."
5157
+ },
5158
+ {
5159
+ "kind": "function",
5160
+ "name": "defineStatefulAgent",
5161
+ "return": {
5162
+ "type": {
5163
+ "text": "AgentConfig"
5164
+ }
5165
+ },
5166
+ "parameters": [
5167
+ {
5168
+ "name": "opts",
5169
+ "type": {
5170
+ "text": "StatefulAgentInit<S>"
5018
5171
  }
5019
5172
  }
5020
5173
  ],
5021
- "description": "Set it for one session, announcing `autopilot-needs-user` when it changes."
5174
+ "description": "Build an `AgentConfig` whose `systemPrompt`, `toolDefinitions`, and tool\nhandlers all close over a long-lived state object created on activation.\n\nThe framework wires the lifecycle: `init` on `onActivate`, `dispose` on\n`onDeactivate`. State is held inside the helper's closure — never exposed on\nthe resulting `AgentConfig` — so the redux serializer doesn't see it."
5022
5175
  },
5023
5176
  {
5024
5177
  "kind": "function",
5025
- "name": "autopilotNeedsUser",
5178
+ "name": "defineAutopilot",
5026
5179
  "return": {
5027
5180
  "type": {
5028
- "text": "boolean"
5181
+ "text": "AutopilotConfig<S>"
5029
5182
  }
5030
5183
  },
5031
5184
  "parameters": [
5032
5185
  {
5033
- "name": "sessionKey",
5034
- "optional": true,
5186
+ "name": "config",
5035
5187
  "type": {
5036
- "text": "string"
5188
+ "text": "AutopilotConfig<S>"
5037
5189
  }
5038
5190
  }
5039
5191
  ],
5040
- "description": "Whether a session has something waiting on the person — or, without a key (a bubble that cannot\ntell which assistant it holds), whether any session has."
5192
+ "description": "Define an autopilot for a stateful agent whose state is `S` (GENC-1660). An identity function\nthat exists for its type: the resolvers get `S`, and the result goes on `defineStatefulAgent`'s\n`autopilot` option."
5193
+ }
5194
+ ],
5195
+ "exports": [
5196
+ {
5197
+ "kind": "js",
5198
+ "name": "restoreMachine",
5199
+ "declaration": {
5200
+ "name": "restoreMachine",
5201
+ "module": "src/config/define-stateful-agent.ts"
5202
+ }
5203
+ },
5204
+ {
5205
+ "kind": "js",
5206
+ "name": "defineStatefulAgent",
5207
+ "declaration": {
5208
+ "name": "defineStatefulAgent",
5209
+ "module": "src/config/define-stateful-agent.ts"
5210
+ }
5211
+ },
5212
+ {
5213
+ "kind": "js",
5214
+ "name": "defineAutopilot",
5215
+ "declaration": {
5216
+ "name": "defineAutopilot",
5217
+ "module": "src/config/define-stateful-agent.ts"
5218
+ }
5219
+ }
5220
+ ]
5221
+ },
5222
+ {
5223
+ "kind": "javascript-module",
5224
+ "path": "src/config/fallback-agents.ts",
5225
+ "declarations": [
5226
+ {
5227
+ "kind": "variable",
5228
+ "name": "friendlyFallbackAgent",
5229
+ "type": {
5230
+ "text": "FallbackAgentConfig"
5231
+ },
5232
+ "default": "{\n name: 'Assistant',\n fallback: true,\n systemPrompt: `You are a warm, friendly assistant. For general conversation like \"Hi\" or \"How are you\", you can have a friendly chat. For anything more complex, you cannot directly help, but you can explain what specialists are available. The available specialists are:\\n\\n{{agents}}\\n\\nPolitely let the user know what you can help with and invite them to rephrase their request if it is outside your scope.`,\n}",
5233
+ "description": "A warm, conversational fallback agent. Acknowledges it can't help directly,\nexplains what the available specialists can do, and invites the user to retry.\n\nThe system prompt is generated at runtime by `OrchestratingDriver` from the\nspecialist list — no manual authoring required."
5234
+ },
5235
+ {
5236
+ "kind": "variable",
5237
+ "name": "strictFallbackAgent",
5238
+ "type": {
5239
+ "text": "FallbackAgentConfig"
5240
+ },
5241
+ "default": "{\n name: 'Assistant',\n fallback: true,\n systemPrompt: `You are a concise assistant. The user's request is outside your scope. The available specialists are: {{agents}}.\n\n{{unroutable}}\n\nAnswer in a single short sentence. Do not elaborate.`,\n}",
5242
+ "description": "A brief, professional fallback agent. States what is available without\nelaboration. The `{{agents}}` placeholder is replaced at runtime by\n`OrchestratingDriver` with the generated specialist list.\n\nThe `{{unroutable}}` placeholder positions `UNROUTABLE_INSTRUCTION` — the framework's\ninstruction for a substantive request no specialist covers, which is otherwise APPENDED to a\nstring-form prompt. Positioned rather than appended for one reason: this preset's whole point is\nbrevity, and appended text would be the last thing the model reads. Putting the block above the\nbrevity rule leaves \"a single short sentence\" with the recency, so the two compose instead of\ncompeting. A prompt whose tone rules matter should do the same."
5041
5243
  }
5042
5244
  ],
5043
5245
  "exports": [
5044
5246
  {
5045
5247
  "kind": "js",
5046
- "name": "setAutopilotNeedsUser",
5248
+ "name": "friendlyFallbackAgent",
5249
+ "declaration": {
5250
+ "name": "friendlyFallbackAgent",
5251
+ "module": "src/config/fallback-agents.ts"
5252
+ }
5253
+ },
5254
+ {
5255
+ "kind": "js",
5256
+ "name": "strictFallbackAgent",
5257
+ "declaration": {
5258
+ "name": "strictFallbackAgent",
5259
+ "module": "src/config/fallback-agents.ts"
5260
+ }
5261
+ }
5262
+ ]
5263
+ },
5264
+ {
5265
+ "kind": "javascript-module",
5266
+ "path": "src/config/index.ts",
5267
+ "declarations": [],
5268
+ "exports": [
5269
+ {
5270
+ "kind": "js",
5271
+ "name": "*",
5047
5272
  "declaration": {
5048
- "name": "setAutopilotNeedsUser",
5049
- "module": "src/channel/autopilot-needs-user.ts"
5273
+ "name": "*",
5274
+ "package": "./config"
5050
5275
  }
5051
5276
  },
5052
5277
  {
5053
5278
  "kind": "js",
5054
- "name": "autopilotNeedsUser",
5279
+ "name": "*",
5055
5280
  "declaration": {
5056
- "name": "autopilotNeedsUser",
5057
- "module": "src/channel/autopilot-needs-user.ts"
5281
+ "name": "*",
5282
+ "package": "./fallback-agents"
5058
5283
  }
5059
5284
  }
5060
5285
  ]
5061
5286
  },
5287
+ {
5288
+ "kind": "javascript-module",
5289
+ "path": "src/config/validate-providers.ts",
5290
+ "declarations": [],
5291
+ "exports": []
5292
+ },
5062
5293
  {
5063
5294
  "kind": "javascript-module",
5064
5295
  "path": "src/components/flowing-waves-indicator.ts",
@@ -5527,293 +5758,62 @@
5527
5758
  }
5528
5759
  },
5529
5760
  "parameters": [
5530
- {
5531
- "name": "cfg",
5532
- "type": {
5533
- "text": "WaveConfig"
5534
- }
5535
- },
5536
- {
5537
- "name": "frame",
5538
- "type": {
5539
- "text": "number"
5540
- }
5541
- }
5542
- ],
5543
- "description": "Trace one wave's polyline `d` attribute for the given frame."
5544
- }
5545
- ],
5546
- "attributes": [
5547
- {
5548
- "type": {
5549
- "text": "number"
5550
- },
5551
- "default": "WAVES_DEFAULT_SIZE",
5552
- "description": "Diameter of the circular window in px. Default: 56.",
5553
- "resolveInitializer": {
5554
- "module": "src/components/waves-indicator.ts"
5555
- },
5556
- "fieldName": "size"
5557
- }
5558
- ],
5559
- "superclass": {
5560
- "name": "GenesisElement",
5561
- "package": "@genesislcap/web-core"
5562
- },
5563
- "tagName": "ai-waves-indicator",
5564
- "customElement": true
5565
- }
5566
- ],
5567
- "exports": [
5568
- {
5569
- "kind": "js",
5570
- "name": "AiWavesIndicator",
5571
- "declaration": {
5572
- "name": "AiWavesIndicator",
5573
- "module": "src/components/waves-indicator.ts"
5574
- }
5575
- },
5576
- {
5577
- "kind": "custom-element-definition",
5578
- "name": "ai-waves-indicator",
5579
- "declaration": {
5580
- "name": "AiWavesIndicator",
5581
- "module": "src/components/waves-indicator.ts"
5582
- }
5583
- }
5584
- ]
5585
- },
5586
- {
5587
- "kind": "javascript-module",
5588
- "path": "src/config/config.ts",
5589
- "declarations": [
5590
- {
5591
- "kind": "function",
5592
- "name": "defineAgent",
5593
- "description": "Identity helper that infers the narrowest possible type for an agent config,\npreserving string literal types (including `name`) without requiring `as const`.\n\nUse this when you need `typeof myAgent` to carry the literal `name` type —\nfor example, when wiring `ChatToolHandlers<typeof myAgent>`.\n\n```ts\nconst myAgent = defineAgent({ name: 'my_agent', ... });\ntype Handlers = ChatToolHandlers<typeof myAgent>;\n// requestSubAgent name param is now typed as 'my_agent'\n```"
5594
- }
5595
- ],
5596
- "exports": [
5597
- {
5598
- "kind": "js",
5599
- "name": "CachePolicy",
5600
- "declaration": {
5601
- "name": "CachePolicy",
5602
- "module": "src/config/config.ts"
5603
- }
5604
- },
5605
- {
5606
- "kind": "js",
5607
- "name": "ChatFallback",
5608
- "declaration": {
5609
- "name": "ChatFallback",
5610
- "module": "src/config/config.ts"
5611
- }
5612
- },
5613
- {
5614
- "kind": "js",
5615
- "name": "ChatInputDuringExecutionMode",
5616
- "declaration": {
5617
- "name": "ChatInputDuringExecutionMode",
5618
- "module": "src/config/config.ts"
5619
- }
5620
- },
5621
- {
5622
- "kind": "js",
5623
- "name": "ChatThinkingPolicy",
5624
- "declaration": {
5625
- "name": "ChatThinkingPolicy",
5626
- "module": "src/config/config.ts"
5627
- }
5628
- },
5629
- {
5630
- "kind": "js",
5631
- "name": "ChatToolChoice",
5632
- "declaration": {
5633
- "name": "ChatToolChoice",
5634
- "module": "src/config/config.ts"
5635
- }
5636
- },
5637
- {
5638
- "kind": "js",
5639
- "name": "defineAgent",
5640
- "declaration": {
5641
- "name": "defineAgent",
5642
- "module": "src/config/config.ts"
5643
- }
5644
- }
5645
- ]
5646
- },
5647
- {
5648
- "kind": "javascript-module",
5649
- "path": "src/config/define-stateful-agent.ts",
5650
- "declarations": [
5651
- {
5652
- "kind": "function",
5653
- "name": "restoreMachine",
5654
- "return": {
5655
- "type": {
5656
- "text": "void"
5657
- }
5658
- },
5659
- "parameters": [
5660
- {
5661
- "name": "machine",
5662
- "type": {
5663
- "text": "{ stop: () => void; start: (options?: { state?: unknown }) => void }"
5664
- },
5665
- "description": "the machine to restore (already constructed/started)."
5666
- },
5667
- {
5668
- "name": "restored",
5669
- "type": {
5670
- "text": "unknown"
5671
- },
5672
- "description": "the agent's serialized image (`ctx.restored` in `init`)."
5673
- },
5674
- {
5675
- "name": "key",
5676
- "default": "'machine'",
5677
- "description": "the property the machine occupies in the snapshot; defaults to\n`'machine'` to match the conventional `{ machine }` state bag."
5678
- }
5679
- ],
5680
- "description": "Restore a foundation-state-machine instance from a snapshot produced by the\ndefault serializer (or `machine.getPersistedSnapshot()`). Call inside a\nstateful agent's `init` to resume the machine in its exact prior place:\n\n```ts\ninit: ({ restored }) => {\n const machine = new MyMachine();\n restoreMachine(machine, restored); // resume, or no-op on a fresh start\n return { machine };\n}\n```\n\nNo-ops when there is nothing to restore (a fresh session), leaving the\nfreshly-constructed machine in its initial state."
5681
- },
5682
- {
5683
- "kind": "function",
5684
- "name": "defineStatefulAgent",
5685
- "return": {
5686
- "type": {
5687
- "text": "AgentConfig"
5688
- }
5689
- },
5690
- "parameters": [
5691
- {
5692
- "name": "opts",
5693
- "type": {
5694
- "text": "StatefulAgentInit<S>"
5695
- }
5696
- }
5697
- ],
5698
- "description": "Build an `AgentConfig` whose `systemPrompt`, `toolDefinitions`, and tool\nhandlers all close over a long-lived state object created on activation.\n\nThe framework wires the lifecycle: `init` on `onActivate`, `dispose` on\n`onDeactivate`. State is held inside the helper's closure — never exposed on\nthe resulting `AgentConfig` — so the redux serializer doesn't see it."
5699
- },
5700
- {
5701
- "kind": "function",
5702
- "name": "defineAutopilot",
5703
- "return": {
5704
- "type": {
5705
- "text": "AutopilotConfig<S>"
5706
- }
5707
- },
5708
- "parameters": [
5709
- {
5710
- "name": "config",
5711
- "type": {
5712
- "text": "AutopilotConfig<S>"
5713
- }
5714
- }
5715
- ],
5716
- "description": "Define an autopilot for a stateful agent whose state is `S` (GENC-1660). An identity function\nthat exists for its type: the resolvers get `S`, and the result goes on `defineStatefulAgent`'s\n`autopilot` option."
5717
- }
5718
- ],
5719
- "exports": [
5720
- {
5721
- "kind": "js",
5722
- "name": "restoreMachine",
5723
- "declaration": {
5724
- "name": "restoreMachine",
5725
- "module": "src/config/define-stateful-agent.ts"
5726
- }
5727
- },
5728
- {
5729
- "kind": "js",
5730
- "name": "defineStatefulAgent",
5731
- "declaration": {
5732
- "name": "defineStatefulAgent",
5733
- "module": "src/config/define-stateful-agent.ts"
5734
- }
5735
- },
5736
- {
5737
- "kind": "js",
5738
- "name": "defineAutopilot",
5739
- "declaration": {
5740
- "name": "defineAutopilot",
5741
- "module": "src/config/define-stateful-agent.ts"
5742
- }
5743
- }
5744
- ]
5745
- },
5746
- {
5747
- "kind": "javascript-module",
5748
- "path": "src/config/fallback-agents.ts",
5749
- "declarations": [
5750
- {
5751
- "kind": "variable",
5752
- "name": "friendlyFallbackAgent",
5753
- "type": {
5754
- "text": "FallbackAgentConfig"
5755
- },
5756
- "default": "{\n name: 'Assistant',\n fallback: true,\n systemPrompt: `You are a warm, friendly assistant. For general conversation like \"Hi\" or \"How are you\", you can have a friendly chat. For anything more complex, you cannot directly help, but you can explain what specialists are available. The available specialists are:\\n\\n{{agents}}\\n\\nPolitely let the user know what you can help with and invite them to rephrase their request if it is outside your scope.`,\n}",
5757
- "description": "A warm, conversational fallback agent. Acknowledges it can't help directly,\nexplains what the available specialists can do, and invites the user to retry.\n\nThe system prompt is generated at runtime by `OrchestratingDriver` from the\nspecialist list — no manual authoring required."
5758
- },
5759
- {
5760
- "kind": "variable",
5761
- "name": "strictFallbackAgent",
5762
- "type": {
5763
- "text": "FallbackAgentConfig"
5761
+ {
5762
+ "name": "cfg",
5763
+ "type": {
5764
+ "text": "WaveConfig"
5765
+ }
5766
+ },
5767
+ {
5768
+ "name": "frame",
5769
+ "type": {
5770
+ "text": "number"
5771
+ }
5772
+ }
5773
+ ],
5774
+ "description": "Trace one wave's polyline `d` attribute for the given frame."
5775
+ }
5776
+ ],
5777
+ "attributes": [
5778
+ {
5779
+ "type": {
5780
+ "text": "number"
5781
+ },
5782
+ "default": "WAVES_DEFAULT_SIZE",
5783
+ "description": "Diameter of the circular window in px. Default: 56.",
5784
+ "resolveInitializer": {
5785
+ "module": "src/components/waves-indicator.ts"
5786
+ },
5787
+ "fieldName": "size"
5788
+ }
5789
+ ],
5790
+ "superclass": {
5791
+ "name": "GenesisElement",
5792
+ "package": "@genesislcap/web-core"
5764
5793
  },
5765
- "default": "{\n name: 'Assistant',\n fallback: true,\n systemPrompt: `You are a concise assistant. The user's request is outside your scope. The available specialists are: {{agents}}.\n\n{{unroutable}}\n\nAnswer in a single short sentence. Do not elaborate.`,\n}",
5766
- "description": "A brief, professional fallback agent. States what is available without\nelaboration. The `{{agents}}` placeholder is replaced at runtime by\n`OrchestratingDriver` with the generated specialist list.\n\nThe `{{unroutable}}` placeholder positions `UNROUTABLE_INSTRUCTION` — the framework's\ninstruction for a substantive request no specialist covers, which is otherwise APPENDED to a\nstring-form prompt. Positioned rather than appended for one reason: this preset's whole point is\nbrevity, and appended text would be the last thing the model reads. Putting the block above the\nbrevity rule leaves \"a single short sentence\" with the recency, so the two compose instead of\ncompeting. A prompt whose tone rules matter should do the same."
5794
+ "tagName": "ai-waves-indicator",
5795
+ "customElement": true
5767
5796
  }
5768
5797
  ],
5769
5798
  "exports": [
5770
5799
  {
5771
5800
  "kind": "js",
5772
- "name": "friendlyFallbackAgent",
5773
- "declaration": {
5774
- "name": "friendlyFallbackAgent",
5775
- "module": "src/config/fallback-agents.ts"
5776
- }
5777
- },
5778
- {
5779
- "kind": "js",
5780
- "name": "strictFallbackAgent",
5781
- "declaration": {
5782
- "name": "strictFallbackAgent",
5783
- "module": "src/config/fallback-agents.ts"
5784
- }
5785
- }
5786
- ]
5787
- },
5788
- {
5789
- "kind": "javascript-module",
5790
- "path": "src/config/index.ts",
5791
- "declarations": [],
5792
- "exports": [
5793
- {
5794
- "kind": "js",
5795
- "name": "*",
5801
+ "name": "AiWavesIndicator",
5796
5802
  "declaration": {
5797
- "name": "*",
5798
- "package": "./config"
5803
+ "name": "AiWavesIndicator",
5804
+ "module": "src/components/waves-indicator.ts"
5799
5805
  }
5800
5806
  },
5801
5807
  {
5802
- "kind": "js",
5803
- "name": "*",
5808
+ "kind": "custom-element-definition",
5809
+ "name": "ai-waves-indicator",
5804
5810
  "declaration": {
5805
- "name": "*",
5806
- "package": "./fallback-agents"
5811
+ "name": "AiWavesIndicator",
5812
+ "module": "src/components/waves-indicator.ts"
5807
5813
  }
5808
5814
  }
5809
5815
  ]
5810
5816
  },
5811
- {
5812
- "kind": "javascript-module",
5813
- "path": "src/config/validate-providers.ts",
5814
- "declarations": [],
5815
- "exports": []
5816
- },
5817
5817
  {
5818
5818
  "kind": "javascript-module",
5819
5819
  "path": "src/genesis/calendar.ts",
@@ -6972,202 +6972,28 @@
6972
6972
  {
6973
6973
  "name": "options",
6974
6974
  "default": "{}",
6975
- "type": {
6976
- "text": "GenesisWriteToolsOptions"
6977
- }
6978
- }
6979
- ],
6980
- "description": "Builds the assistant's write tools from an app's event resources."
6981
- }
6982
- ],
6983
- "exports": [
6984
- {
6985
- "kind": "js",
6986
- "name": "createGenesisWriteTools",
6987
- "declaration": {
6988
- "name": "createGenesisWriteTools",
6989
- "module": "src/genesis/write-tools.ts"
6990
- }
6991
- }
6992
- ]
6993
- },
6994
- {
6995
- "kind": "javascript-module",
6996
- "path": "src/genesis/write-turn.ts",
6997
- "declarations": [],
6998
- "exports": []
6999
- },
7000
- {
7001
- "kind": "javascript-module",
7002
- "path": "src/notifications/agent-notifications.ts",
7003
- "declarations": [
7004
- {
7005
- "kind": "variable",
7006
- "name": "DEFAULT_AGENT_NOTIFICATION_MESSAGE",
7007
- "type": {
7008
- "text": "string"
7009
- },
7010
- "default": "'The assistant is ready for your next input'",
7011
- "description": "The notification's text when neither the app nor the widget gives one."
7012
- },
7013
- {
7014
- "kind": "function",
7015
- "name": "agentNotificationPermission",
7016
- "return": {
7017
- "type": {
7018
- "text": "AgentNotificationPermission"
7019
- }
7020
- },
7021
- "description": "Whether this page may show notifications. Safe to call anywhere, including Node."
7022
- },
7023
- {
7024
- "kind": "function",
7025
- "name": "requestAgentNotificationPermission",
7026
- "return": {
7027
- "type": {
7028
- "text": "Promise<AgentNotificationPermission>"
7029
- }
7030
- },
7031
- "description": "Ask the person for permission to show notifications, and resolve to the result. Call it from a\nclick or key handler: browsers ignore or refuse a request that does not come from the person.\nResolves straight away when permission is already decided or unsupported, since a browser only\never asks once."
7032
- }
7033
- ],
7034
- "exports": [
7035
- {
7036
- "kind": "js",
7037
- "name": "DEFAULT_AGENT_NOTIFICATION_MESSAGE",
7038
- "declaration": {
7039
- "name": "DEFAULT_AGENT_NOTIFICATION_MESSAGE",
7040
- "module": "src/notifications/agent-notifications.ts"
7041
- }
7042
- },
7043
- {
7044
- "kind": "js",
7045
- "name": "agentNotificationPermission",
7046
- "declaration": {
7047
- "name": "agentNotificationPermission",
7048
- "module": "src/notifications/agent-notifications.ts"
7049
- }
7050
- },
7051
- {
7052
- "kind": "js",
7053
- "name": "requestAgentNotificationPermission",
7054
- "declaration": {
7055
- "name": "requestAgentNotificationPermission",
7056
- "module": "src/notifications/agent-notifications.ts"
7057
- }
7058
- }
7059
- ]
7060
- },
7061
- {
7062
- "kind": "javascript-module",
7063
- "path": "src/notifications/agent-notifier.ts",
7064
- "declarations": [],
7065
- "exports": []
7066
- },
7067
- {
7068
- "kind": "javascript-module",
7069
- "path": "src/notifications/index.ts",
7070
- "declarations": [],
7071
- "exports": [
7072
- {
7073
- "kind": "js",
7074
- "name": "agentNotificationPermission",
7075
- "declaration": {
7076
- "name": "agentNotificationPermission",
7077
- "module": "./agent-notifications"
7078
- }
7079
- },
7080
- {
7081
- "kind": "js",
7082
- "name": "DEFAULT_AGENT_NOTIFICATION_MESSAGE",
7083
- "declaration": {
7084
- "name": "DEFAULT_AGENT_NOTIFICATION_MESSAGE",
7085
- "module": "./agent-notifications"
7086
- }
7087
- },
7088
- {
7089
- "kind": "js",
7090
- "name": "requestAgentNotificationPermission",
7091
- "declaration": {
7092
- "name": "requestAgentNotificationPermission",
7093
- "module": "./agent-notifications"
7094
- }
7095
- },
7096
- {
7097
- "kind": "js",
7098
- "name": "type",
7099
- "declaration": {
7100
- "name": "type",
7101
- "module": "./agent-notifications"
7102
- }
7103
- },
7104
- {
7105
- "kind": "js",
7106
- "name": "AgentAttentionDetail",
7107
- "declaration": {
7108
- "name": "AgentAttentionDetail",
7109
- "module": "./agent-notifications"
7110
- }
7111
- },
7112
- {
7113
- "kind": "js",
7114
- "name": "type",
7115
- "declaration": {
7116
- "name": "type",
7117
- "module": "./agent-notifications"
7118
- }
7119
- },
7120
- {
7121
- "kind": "js",
7122
- "name": "AgentAttentionKind",
7123
- "declaration": {
7124
- "name": "AgentAttentionKind",
7125
- "module": "./agent-notifications"
7126
- }
7127
- },
7128
- {
7129
- "kind": "js",
7130
- "name": "type",
7131
- "declaration": {
7132
- "name": "type",
7133
- "module": "./agent-notifications"
7134
- }
7135
- },
7136
- {
7137
- "kind": "js",
7138
- "name": "AgentNotificationLevel",
7139
- "declaration": {
7140
- "name": "AgentNotificationLevel",
7141
- "module": "./agent-notifications"
7142
- }
7143
- },
7144
- {
7145
- "kind": "js",
7146
- "name": "type",
7147
- "declaration": {
7148
- "name": "type",
7149
- "module": "./agent-notifications"
7150
- }
7151
- },
6975
+ "type": {
6976
+ "text": "GenesisWriteToolsOptions"
6977
+ }
6978
+ }
6979
+ ],
6980
+ "description": "Builds the assistant's write tools from an app's event resources."
6981
+ }
6982
+ ],
6983
+ "exports": [
7152
6984
  {
7153
6985
  "kind": "js",
7154
- "name": "AgentNotificationPermission",
6986
+ "name": "createGenesisWriteTools",
7155
6987
  "declaration": {
7156
- "name": "AgentNotificationPermission",
7157
- "module": "./agent-notifications"
6988
+ "name": "createGenesisWriteTools",
6989
+ "module": "src/genesis/write-tools.ts"
7158
6990
  }
7159
6991
  }
7160
6992
  ]
7161
6993
  },
7162
6994
  {
7163
6995
  "kind": "javascript-module",
7164
- "path": "src/notifications/notification-level-picker.template.ts",
7165
- "declarations": [],
7166
- "exports": []
7167
- },
7168
- {
7169
- "kind": "javascript-module",
7170
- "path": "src/notifications/notification-settings.ts",
6996
+ "path": "src/genesis/write-turn.ts",
7171
6997
  "declarations": [],
7172
6998
  "exports": []
7173
6999
  },
@@ -7508,6 +7334,15 @@
7508
7334
  },
7509
7335
  "description": "Controls the pop-out button shown next to the settings cog.\n\"expand\" — in bubble, expands to layout panel (fires chat-popout).\n\"collapse\" — in layout panel, collapses back to bubble (fires chat-popin).\nAbsent — no button (default standalone behaviour, no breaking change)."
7510
7336
  },
7337
+ {
7338
+ "kind": "field",
7339
+ "name": "closable",
7340
+ "type": {
7341
+ "text": "boolean"
7342
+ },
7343
+ "default": "false",
7344
+ "description": "Shows a Close button in the header, which fires `close-requested` and leaves the closing to\nwhatever holds the assistant. The chat bubble sets it while the assistant is in its dialog."
7345
+ },
7511
7346
  {
7512
7347
  "kind": "field",
7513
7348
  "name": "agents",
@@ -11064,6 +10899,16 @@
11064
10899
  ],
11065
10900
  "description": "Report a turn that ended with the assistant waiting for the person to type (GENC-1660), for the\nAlways level: `turn-ended` on the activity bus, like every other notification report.\n\nOnly for a turn that ran to its end, failed ones included: not one the person stopped\n(`cancelling`), since they are there. Not while an interaction waits on them, which reports\nitself, so the person is never told twice about one moment. And not while an autopilot runs for\nthe flow: it answers, hands back or reports its own stop. Sub-agents' turns never get here; they\nrun inside one of the parent's."
11066
10901
  },
10902
+ {
10903
+ "kind": "method",
10904
+ "name": "handleClose",
10905
+ "return": {
10906
+ "type": {
10907
+ "text": "void"
10908
+ }
10909
+ },
10910
+ "description": "Called when the user clicks the header's Close button."
10911
+ },
11067
10912
  {
11068
10913
  "kind": "method",
11069
10914
  "name": "onChatHeaderMouseDown",
@@ -11205,6 +11050,10 @@
11205
11050
  "description": "Fired when the user presses the chat header in `popout-mode=\"expand\"` (for drag-to-popout hosts). Bubbles and composed. detail: `ChatHeaderMouseDownDetail`",
11206
11051
  "name": "chat-header-mousedown"
11207
11052
  },
11053
+ {
11054
+ "description": "Fired when the user presses the header's Close button, which shows while `closable` is set (the chat bubble sets it while the assistant is in its dialog). Bubbles and composed.",
11055
+ "name": "close-requested"
11056
+ },
11208
11057
  {
11209
11058
  "description": "Fired after the session is wiped (the lifecycle menu's Clear). The payload is captured before teardown so the host can clean up any external state the active agent was working on. Bubbles and composed. detail: `SessionClearedDetail`",
11210
11059
  "name": "session-cleared"
@@ -11269,6 +11118,14 @@
11269
11118
  "description": "Controls the pop-out button shown next to the settings cog.\n\"expand\" — in bubble, expands to layout panel (fires chat-popout).\n\"collapse\" — in layout panel, collapses back to bubble (fires chat-popin).\nAbsent — no button (default standalone behaviour, no breaking change).",
11270
11119
  "fieldName": "popoutMode"
11271
11120
  },
11121
+ {
11122
+ "type": {
11123
+ "text": "boolean"
11124
+ },
11125
+ "default": "false",
11126
+ "description": "Shows a Close button in the header, which fires `close-requested` and leaves the closing to\nwhatever holds the assistant. The chat bubble sets it while the assistant is in its dialog.",
11127
+ "fieldName": "closable"
11128
+ },
11272
11129
  {
11273
11130
  "name": "debug-redux",
11274
11131
  "type": {
@@ -11354,9 +11211,9 @@
11354
11211
  "kind": "variable",
11355
11212
  "name": "AiAssistantEvent",
11356
11213
  "type": {
11357
- "text": "{\n /** Session wiped via the lifecycle menu's Clear. `detail`: `SessionClearedDetail`. */\n SessionCleared: 'session-cleared',\n /** Header pressed in `popout-mode=\"expand\"` (drag-to-popout hosts). `detail`: `ChatHeaderMouseDownDetail`. */\n ChatHeaderMouseDown: 'chat-header-mousedown',\n /** An agent's hand-off started (GENC-1737). `detail`: `HandOffFrame`. */\n HandOffStarted: 'handoff-started',\n /** A hand-off ended and its caller is active again. `detail`: `HandOffFrame`, with `outcome`. */\n HandOffReturned: 'handoff-returned',\n /** A hand-off ended with no hand-back. `detail`: `HandOffFrame`, with `outcome`. */\n HandOffUnwound: 'handoff-unwound',\n}"
11214
+ "text": "{\n /** Session wiped via the lifecycle menu's Clear. `detail`: `SessionClearedDetail`. */\n SessionCleared: 'session-cleared',\n /** Header pressed in `popout-mode=\"expand\"` (drag-to-popout hosts). `detail`: `ChatHeaderMouseDownDetail`. */\n ChatHeaderMouseDown: 'chat-header-mousedown',\n /** An agent's hand-off started (GENC-1737). `detail`: `HandOffFrame`. */\n HandOffStarted: 'handoff-started',\n /** A hand-off ended and its caller is active again. `detail`: `HandOffFrame`, with `outcome`. */\n HandOffReturned: 'handoff-returned',\n /** A hand-off ended with no hand-back. `detail`: `HandOffFrame`, with `outcome`. */\n HandOffUnwound: 'handoff-unwound',\n /** The header's Close button pressed, shown while `closable` is set. No `detail`. */\n CloseRequested: 'close-requested',\n}"
11358
11215
  },
11359
- "default": "{\n /** Session wiped via the lifecycle menu's Clear. `detail`: `SessionClearedDetail`. */\n SessionCleared: 'session-cleared',\n /** Header pressed in `popout-mode=\"expand\"` (drag-to-popout hosts). `detail`: `ChatHeaderMouseDownDetail`. */\n ChatHeaderMouseDown: 'chat-header-mousedown',\n /** An agent's hand-off started (GENC-1737). `detail`: `HandOffFrame`. */\n HandOffStarted: 'handoff-started',\n /** A hand-off ended and its caller is active again. `detail`: `HandOffFrame`, with `outcome`. */\n HandOffReturned: 'handoff-returned',\n /** A hand-off ended with no hand-back. `detail`: `HandOffFrame`, with `outcome`. */\n HandOffUnwound: 'handoff-unwound',\n}",
11216
+ "default": "{\n /** Session wiped via the lifecycle menu's Clear. `detail`: `SessionClearedDetail`. */\n SessionCleared: 'session-cleared',\n /** Header pressed in `popout-mode=\"expand\"` (drag-to-popout hosts). `detail`: `ChatHeaderMouseDownDetail`. */\n ChatHeaderMouseDown: 'chat-header-mousedown',\n /** An agent's hand-off started (GENC-1737). `detail`: `HandOffFrame`. */\n HandOffStarted: 'handoff-started',\n /** A hand-off ended and its caller is active again. `detail`: `HandOffFrame`, with `outcome`. */\n HandOffReturned: 'handoff-returned',\n /** A hand-off ended with no hand-back. `detail`: `HandOffFrame`, with `outcome`. */\n HandOffUnwound: 'handoff-unwound',\n /** The header's Close button pressed, shown while `closable` is set. No `detail`. */\n CloseRequested: 'close-requested',\n}",
11360
11217
  "description": "DOM events the `<foundation-ai-assistant>` element dispatches to its host.\nAll bubble and are `composed` (they cross the shadow boundary), so a host can\nlisten on the element — or any ancestor — to react. Use these constants to\nwire listeners instead of hand-typing event-name strings.\n\nAn `as const` map (not a TS `enum` — this package ships none), so it serves as\nboth the listener-name value and, via the same-named type below, a union."
11361
11218
  },
11362
11219
  {
@@ -11428,6 +11285,180 @@
11428
11285
  "declarations": [],
11429
11286
  "exports": []
11430
11287
  },
11288
+ {
11289
+ "kind": "javascript-module",
11290
+ "path": "src/notifications/agent-notifications.ts",
11291
+ "declarations": [
11292
+ {
11293
+ "kind": "variable",
11294
+ "name": "DEFAULT_AGENT_NOTIFICATION_MESSAGE",
11295
+ "type": {
11296
+ "text": "string"
11297
+ },
11298
+ "default": "'The assistant is ready for your next input'",
11299
+ "description": "The notification's text when neither the app nor the widget gives one."
11300
+ },
11301
+ {
11302
+ "kind": "function",
11303
+ "name": "agentNotificationPermission",
11304
+ "return": {
11305
+ "type": {
11306
+ "text": "AgentNotificationPermission"
11307
+ }
11308
+ },
11309
+ "description": "Whether this page may show notifications. Safe to call anywhere, including Node."
11310
+ },
11311
+ {
11312
+ "kind": "function",
11313
+ "name": "requestAgentNotificationPermission",
11314
+ "return": {
11315
+ "type": {
11316
+ "text": "Promise<AgentNotificationPermission>"
11317
+ }
11318
+ },
11319
+ "description": "Ask the person for permission to show notifications, and resolve to the result. Call it from a\nclick or key handler: browsers ignore or refuse a request that does not come from the person.\nResolves straight away when permission is already decided or unsupported, since a browser only\never asks once."
11320
+ }
11321
+ ],
11322
+ "exports": [
11323
+ {
11324
+ "kind": "js",
11325
+ "name": "DEFAULT_AGENT_NOTIFICATION_MESSAGE",
11326
+ "declaration": {
11327
+ "name": "DEFAULT_AGENT_NOTIFICATION_MESSAGE",
11328
+ "module": "src/notifications/agent-notifications.ts"
11329
+ }
11330
+ },
11331
+ {
11332
+ "kind": "js",
11333
+ "name": "agentNotificationPermission",
11334
+ "declaration": {
11335
+ "name": "agentNotificationPermission",
11336
+ "module": "src/notifications/agent-notifications.ts"
11337
+ }
11338
+ },
11339
+ {
11340
+ "kind": "js",
11341
+ "name": "requestAgentNotificationPermission",
11342
+ "declaration": {
11343
+ "name": "requestAgentNotificationPermission",
11344
+ "module": "src/notifications/agent-notifications.ts"
11345
+ }
11346
+ }
11347
+ ]
11348
+ },
11349
+ {
11350
+ "kind": "javascript-module",
11351
+ "path": "src/notifications/agent-notifier.ts",
11352
+ "declarations": [],
11353
+ "exports": []
11354
+ },
11355
+ {
11356
+ "kind": "javascript-module",
11357
+ "path": "src/notifications/index.ts",
11358
+ "declarations": [],
11359
+ "exports": [
11360
+ {
11361
+ "kind": "js",
11362
+ "name": "agentNotificationPermission",
11363
+ "declaration": {
11364
+ "name": "agentNotificationPermission",
11365
+ "module": "./agent-notifications"
11366
+ }
11367
+ },
11368
+ {
11369
+ "kind": "js",
11370
+ "name": "DEFAULT_AGENT_NOTIFICATION_MESSAGE",
11371
+ "declaration": {
11372
+ "name": "DEFAULT_AGENT_NOTIFICATION_MESSAGE",
11373
+ "module": "./agent-notifications"
11374
+ }
11375
+ },
11376
+ {
11377
+ "kind": "js",
11378
+ "name": "requestAgentNotificationPermission",
11379
+ "declaration": {
11380
+ "name": "requestAgentNotificationPermission",
11381
+ "module": "./agent-notifications"
11382
+ }
11383
+ },
11384
+ {
11385
+ "kind": "js",
11386
+ "name": "type",
11387
+ "declaration": {
11388
+ "name": "type",
11389
+ "module": "./agent-notifications"
11390
+ }
11391
+ },
11392
+ {
11393
+ "kind": "js",
11394
+ "name": "AgentAttentionDetail",
11395
+ "declaration": {
11396
+ "name": "AgentAttentionDetail",
11397
+ "module": "./agent-notifications"
11398
+ }
11399
+ },
11400
+ {
11401
+ "kind": "js",
11402
+ "name": "type",
11403
+ "declaration": {
11404
+ "name": "type",
11405
+ "module": "./agent-notifications"
11406
+ }
11407
+ },
11408
+ {
11409
+ "kind": "js",
11410
+ "name": "AgentAttentionKind",
11411
+ "declaration": {
11412
+ "name": "AgentAttentionKind",
11413
+ "module": "./agent-notifications"
11414
+ }
11415
+ },
11416
+ {
11417
+ "kind": "js",
11418
+ "name": "type",
11419
+ "declaration": {
11420
+ "name": "type",
11421
+ "module": "./agent-notifications"
11422
+ }
11423
+ },
11424
+ {
11425
+ "kind": "js",
11426
+ "name": "AgentNotificationLevel",
11427
+ "declaration": {
11428
+ "name": "AgentNotificationLevel",
11429
+ "module": "./agent-notifications"
11430
+ }
11431
+ },
11432
+ {
11433
+ "kind": "js",
11434
+ "name": "type",
11435
+ "declaration": {
11436
+ "name": "type",
11437
+ "module": "./agent-notifications"
11438
+ }
11439
+ },
11440
+ {
11441
+ "kind": "js",
11442
+ "name": "AgentNotificationPermission",
11443
+ "declaration": {
11444
+ "name": "AgentNotificationPermission",
11445
+ "module": "./agent-notifications"
11446
+ }
11447
+ }
11448
+ ]
11449
+ },
11450
+ {
11451
+ "kind": "javascript-module",
11452
+ "path": "src/notifications/notification-level-picker.template.ts",
11453
+ "declarations": [],
11454
+ "exports": []
11455
+ },
11456
+ {
11457
+ "kind": "javascript-module",
11458
+ "path": "src/notifications/notification-settings.ts",
11459
+ "declarations": [],
11460
+ "exports": []
11461
+ },
11431
11462
  {
11432
11463
  "kind": "javascript-module",
11433
11464
  "path": "src/provider/ai-provider-switcher.ts",
@@ -17683,11 +17714,12 @@
17683
17714
  },
17684
17715
  {
17685
17716
  "kind": "field",
17686
- "name": "injectedCloseBtn",
17717
+ "name": "closableAssistant",
17687
17718
  "type": {
17688
17719
  "text": "Element | undefined"
17689
17720
  },
17690
- "privacy": "private"
17721
+ "privacy": "private",
17722
+ "description": "The assistant whose header Close button this bubble turned on, and listens to."
17691
17723
  },
17692
17724
  {
17693
17725
  "kind": "field",
@@ -17903,7 +17935,7 @@
17903
17935
  },
17904
17936
  {
17905
17937
  "kind": "method",
17906
- "name": "injectCloseButton",
17938
+ "name": "showCloseButton",
17907
17939
  "privacy": "private",
17908
17940
  "parameters": [
17909
17941
  {
@@ -17912,7 +17944,8 @@
17912
17944
  "text": "Element"
17913
17945
  }
17914
17946
  }
17915
- ]
17947
+ ],
17948
+ "description": "The Close button is the assistant's own, rendered in its header beside the cog. It used to be\na design-system button injected into the assistant's light DOM, where the assistant's styles\ncould reach its host but not the padded control inside it, so it sat narrower than the cog\nand off its centre line, and every host carried a shim to square it up."
17916
17949
  },
17917
17950
  {
17918
17951
  "kind": "method",
@@ -25138,7 +25171,7 @@
25138
25171
  {
25139
25172
  "kind": "variable",
25140
25173
  "name": "WriteReviewStyles",
25141
- "default": "css`\n :host {\n display: block;\n font: inherit;\n\n /* The diff tints — see the diff rules below for why they are backgrounds only. */\n --write-review-added: color-mix(in srgb, var(--success-fill-rest, #2da44e) 18%, transparent);\n --write-review-removed: color-mix(in srgb, var(--error-fill-rest, #cf222e) 18%, transparent);\n }\n\n /*\n * The review mounts inside the chat bubble's dialog content, which is overflow: hidden — so a\n * wide event's columns were CLIPPED rather than pushed off screen, with no scrollbar to say\n * anything was missing. A user approving values they cannot see is the failure this whole\n * component exists to prevent, so the table scrolls within itself.\n */\n .scroller {\n overflow-x: auto;\n max-width: 100%;\n }\n\n table {\n border-collapse: collapse;\n width: 100%;\n }\n\n th,\n td {\n border-bottom: calc(var(--stroke-width, 1) * 1px) solid var(--neutral-stroke-rest);\n padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2px);\n text-align: left;\n }\n\n /* A heading is a column name: kept on one line. */\n th {\n white-space: nowrap;\n }\n\n /*\n * A value is never clipped. Every character stays on screen.\n *\n * Clipping was the first bound, and the wrong one: 24ch with an ellipsis cut the END of every\n * cell, which in a changed cell is the NEW value, so the user approved a value they never saw.\n * No cell is safe to clip either. An insert has no pre-image, so none of its cells is\n * \"changed\", and every one of them is a value being written; a delete's cells are the record\n * being removed; and a title attribute holding the full text reaches nobody on a keyboard or a\n * touch screen.\n *\n * A SHORT value stays whole on one line, and the table scrolls. Wrapping every cell broke a\n * short value mid-token in a squeezed table — \"101.\" over \"2345\" — and the first line could\n * pass for the whole value.\n *\n * A LONG value (review-model marks it) wraps within a bound. With no bound at all, one long\n * value (a NOTE another user wrote) widened its column until the changed one sat out of view,\n * behind a scrollbar an overlay-scrollbar platform does not draw until you scroll.\n */\n td {\n white-space: nowrap;\n }\n\n td.long {\n white-space: normal;\n overflow-wrap: anywhere;\n\n /*\n * A floor as well as a ceiling. With only the ceiling, a squeezed table shrank a long value's\n * column to a sliver (a 100-character note became 22 lines of a few characters each) while\n * the one-line cells kept their width. The table scrolls instead.\n */\n min-width: 20ch;\n max-width: 40ch;\n }\n\n /*\n * The two marks this table carries — \"this field is changing\" and \"this field decides which\n * record disappears\" — were weight, colour and a strike-through only. None of that reaches\n * somebody using a screen reader, who is the one approver with no other way to tell, so each\n * mark has words as well.\n */\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n }\n\n /*\n * A delete shows the whole record and sends its key alone, so the fields that actually decide\n * which record disappears are marked. Not colour alone — an underline carries to a user who\n * cannot distinguish it.\n */\n td.identifying {\n font-weight: 600;\n text-decoration: underline;\n }\n\n /*\n * The diff, the way a code review shows one: what goes is tinted as removed and struck through,\n * what comes in is tinted as added and bold. Only the BACKGROUND is tinted, at low alpha, from\n * the theme's own success and error tokens (with fallbacks, as foundation-forms does), and the\n * text keeps the normal foreground colour: coloured text on a coloured ground is where contrast\n * fails, dark mode first. The tint is never the only signal. Strike-through, weight, the visible\n * + and − marks and the spoken \"was\" and \"now\" all carry the same thing without colour.\n */\n\n /* The mark a user's eye needs: this field is being changed. */\n td.changed {\n font-weight: 600;\n }\n\n /* On its own line above the new value, so neither can push the other out of view. */\n td.changed .was {\n display: block;\n font-weight: 400;\n text-decoration: line-through;\n background: var(--write-review-removed);\n }\n\n td.changed .now {\n display: block;\n background: var(--write-review-added);\n }\n\n /* Room inside the tint, so the − and + do not sit on its edge. */\n td.changed .was,\n td.changed .now {\n padding-inline: calc(var(--design-unit, 4) * 1px);\n }\n\n /*\n * A row that will not be written is never tinted, not even inside a cell. For a refused row\n * review-model already gives it no changed cells, and this is the second guard. For a row the\n * resolved review did not approve, the − and + stay as the record of what was proposed, but\n * without the tint that says it will happen.\n */\n tr.refused td.changed .was,\n tr.refused td.changed .now,\n tr.unwritten td.changed .was,\n tr.unwritten td.changed .now {\n background: none;\n }\n\n /* A whole row coming in, or going. A refused row is neither, and keeps its muted look. */\n tr.added td {\n background: var(--write-review-added);\n }\n\n tr.removed td {\n background: var(--write-review-removed);\n }\n\n /*\n * A closed review's row that was not approved says so in words — without them, a denied modify\n * read in greyscale or by a screen reader exactly like an approved one. An approved row says what\n * came of it the same way, once the write tool has recorded that (written, not written\n * because the user stopped, or its own reason).\n */\n .not-written,\n .fate {\n margin-inline-start: calc(var(--design-unit, 4) * 1.5px);\n font-size: var(--type-ramp-minus-1-font-size, 0.875em);\n color: var(--neutral-foreground-hint);\n }\n\n /*\n * A row action's input is what its handler is given, not a change to the row, so it is labelled\n * rather than marked as a diff. The label is text, so it reaches a screen reader as well.\n */\n .input-mark {\n font-style: italic;\n color: var(--neutral-foreground-hint);\n padding-inline-end: calc(var(--design-unit, 4) * 1px);\n }\n\n .row-action p {\n margin-block: calc(var(--design-unit, 4) * 1px);\n }\n\n /* The empty placeholder: a style no row text can take, so a literal \"(blank)\" cannot pass for it. */\n .blank {\n font-style: italic;\n font-weight: 400;\n color: var(--neutral-foreground-hint);\n }\n\n .mark {\n font-weight: 600;\n padding-inline-end: calc(var(--design-unit, 4) * 1px);\n user-select: none;\n }\n\n /* The row's + or − sits beside its checkbox, not on the baseline under it (where − reads as _). */\n td.select {\n white-space: nowrap;\n }\n\n td.select rapid-checkbox,\n td.select .mark {\n vertical-align: middle;\n }\n\n /* A gap from the checkbox, so the mark reads as the row's sign rather than part of the box. */\n td.select .mark {\n margin-inline-start: calc(var(--design-unit, 4) * 1.5px);\n }\n\n /* The strike-through belongs to the value, not to its − mark. */\n td.changed .was .mark {\n display: inline-block;\n text-decoration: none;\n }\n\n tr.refused {\n color: var(--neutral-foreground-hint);\n }\n\n /* A refusal is a sentence, and it spans the table: it wraps rather than running off it. */\n .problems {\n color: var(--error-fill-rest, #c00);\n white-space: normal;\n }\n\n .actions {\n display: flex;\n gap: calc(var(--design-unit, 4) * 2px);\n margin-top: calc(var(--design-unit, 4) * 2px);\n }\n\n /* The change request takes the width the buttons leave it. */\n .change-request {\n flex: 1 1 24ch;\n }\n\n /* The outcome's live region is always there; while the review is open it takes no room. */\n .closed:empty {\n margin: 0;\n }\n\n /* The count sits at the foot of the field, beside it rather than in its way. */\n .remaining {\n align-self: flex-end;\n white-space: nowrap;\n font-size: var(--type-ramp-minus-1-font-size, 0.875em);\n color: var(--neutral-foreground-hint);\n }\n`"
25174
+ "default": "css`\n :host {\n display: block;\n font: inherit;\n\n /* The diff tints — see the diff rules below for why they are backgrounds only. */\n --write-review-added: color-mix(in srgb, var(--success-fill-rest, #2da44e) 18%, transparent);\n --write-review-removed: color-mix(in srgb, var(--error-fill-rest, #cf222e) 18%, transparent);\n }\n\n /*\n * The review mounts inside the chat bubble's dialog content, which is overflow: hidden — so a\n * wide event's columns were CLIPPED rather than pushed off screen, with no scrollbar to say\n * anything was missing. A user approving values they cannot see is the failure this whole\n * component exists to prevent, so the table scrolls within itself.\n */\n .scroller {\n overflow-x: auto;\n max-width: 100%;\n }\n\n table {\n border-collapse: collapse;\n width: 100%;\n }\n\n th,\n td {\n border-bottom: calc(var(--stroke-width, 1) * 1px) solid var(--neutral-stroke-rest);\n padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2px);\n text-align: left;\n }\n\n /* A heading is a column name: kept on one line. */\n th {\n white-space: nowrap;\n }\n\n /*\n * A value is never clipped. Every character stays on screen.\n *\n * Clipping was the first bound, and the wrong one: 24ch with an ellipsis cut the END of every\n * cell, which in a changed cell is the NEW value, so the user approved a value they never saw.\n * No cell is safe to clip either. An insert has no pre-image, so none of its cells is\n * \"changed\", and every one of them is a value being written; a delete's cells are the record\n * being removed; and a title attribute holding the full text reaches nobody on a keyboard or a\n * touch screen.\n *\n * A SHORT value stays whole on one line, and the table scrolls. Wrapping every cell broke a\n * short value mid-token in a squeezed table — \"101.\" over \"2345\" — and the first line could\n * pass for the whole value.\n *\n * A LONG value (review-model marks it) wraps within a bound. With no bound at all, one long\n * value (a NOTE another user wrote) widened its column until the changed one sat out of view,\n * behind a scrollbar an overlay-scrollbar platform does not draw until you scroll.\n */\n td {\n white-space: nowrap;\n }\n\n td.long {\n white-space: normal;\n overflow-wrap: anywhere;\n\n /*\n * A floor as well as a ceiling. With only the ceiling, a squeezed table shrank a long value's\n * column to a sliver (a 100-character note became 22 lines of a few characters each) while\n * the one-line cells kept their width. The table scrolls instead.\n */\n min-width: 20ch;\n max-width: 40ch;\n }\n\n /*\n * Stacked: the table did not fit (see GenesisWriteReview.stacked), so each row becomes a block\n * and each field a line of its own, its label beside its value, and nothing is off to the side.\n * The headings go, as every value now carries its own; the select-all box stays, labelled.\n */\n .stacked table,\n .stacked tbody,\n .stacked tr,\n .stacked td {\n display: block;\n }\n\n .stacked thead tr {\n display: flex;\n }\n\n .stacked thead th:not(.select) {\n display: none;\n }\n\n .stacked thead th.select {\n border-bottom: none;\n font-weight: 400;\n }\n\n /* Without its column of row boxes beneath it, a lone box at the top says nothing on sight. Its\n spoken name is its aria-label, so the words here are for the eye only (the empty alt). */\n .stacked thead th.select::after {\n content: 'Select all' / '';\n margin-inline-start: calc(var(--design-unit, 4) * 1.5px);\n vertical-align: middle;\n }\n\n .stacked tbody tr {\n padding-block: calc(var(--design-unit, 4) * 1px);\n border-top: calc(var(--stroke-width, 1) * 1px) solid var(--neutral-stroke-rest);\n }\n\n .stacked td {\n border-bottom: none;\n }\n\n .stacked td[data-label] {\n display: grid;\n grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);\n gap: calc(var(--design-unit, 4) * 2px);\n white-space: normal;\n overflow-wrap: anywhere;\n }\n\n .stacked td[data-label]::before {\n content: attr(data-label);\n font-weight: 600;\n }\n\n /* No column to bound any more: a long value takes the line's width like any other, and wraps\n within it like any other. */\n .stacked td.long {\n min-width: 0;\n max-width: none;\n white-space: normal;\n overflow-wrap: anywhere;\n }\n\n /*\n * The two marks this table carries — \"this field is changing\" and \"this field decides which\n * record disappears\" — were weight, colour and a strike-through only. None of that reaches\n * somebody using a screen reader, who is the one approver with no other way to tell, so each\n * mark has words as well.\n */\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n }\n\n /*\n * A delete shows the whole record and sends its key alone, so the fields that actually decide\n * which record disappears are marked. Not colour alone — an underline carries to a user who\n * cannot distinguish it.\n */\n td.identifying {\n font-weight: 600;\n text-decoration: underline;\n }\n\n /*\n * The diff, the way a code review shows one: what goes is tinted as removed and struck through,\n * what comes in is tinted as added and bold. Only the BACKGROUND is tinted, at low alpha, from\n * the theme's own success and error tokens (with fallbacks, as foundation-forms does), and the\n * text keeps the normal foreground colour: coloured text on a coloured ground is where contrast\n * fails, dark mode first. The tint is never the only signal. Strike-through, weight, the visible\n * + and − marks and the spoken \"was\" and \"now\" all carry the same thing without colour.\n */\n\n /* The mark a user's eye needs: this field is being changed. */\n td.changed {\n font-weight: 600;\n }\n\n /* On its own line above the new value, so neither can push the other out of view. */\n td.changed .was {\n display: block;\n font-weight: 400;\n text-decoration: line-through;\n background: var(--write-review-removed);\n }\n\n td.changed .now {\n display: block;\n background: var(--write-review-added);\n }\n\n /* Room inside the tint, so the − and + do not sit on its edge. */\n td.changed .was,\n td.changed .now {\n padding-inline: calc(var(--design-unit, 4) * 1px);\n }\n\n /*\n * A row that will not be written is never tinted, not even inside a cell. For a refused row\n * review-model already gives it no changed cells, and this is the second guard. For a row the\n * resolved review did not approve, the − and + stay as the record of what was proposed, but\n * without the tint that says it will happen.\n */\n tr.refused td.changed .was,\n tr.refused td.changed .now,\n tr.unwritten td.changed .was,\n tr.unwritten td.changed .now {\n background: none;\n }\n\n /* A whole row coming in, or going. A refused row is neither, and keeps its muted look. */\n tr.added td {\n background: var(--write-review-added);\n }\n\n tr.removed td {\n background: var(--write-review-removed);\n }\n\n /*\n * A closed review's row that was not approved says so in words — without them, a denied modify\n * read in greyscale or by a screen reader exactly like an approved one. An approved row says what\n * came of it the same way, once the write tool has recorded that (written, not written\n * because the user stopped, or its own reason).\n */\n .not-written,\n .fate {\n margin-inline-start: calc(var(--design-unit, 4) * 1.5px);\n font-size: var(--type-ramp-minus-1-font-size, 0.875em);\n color: var(--neutral-foreground-hint);\n }\n\n /*\n * A row action's input is what its handler is given, not a change to the row, so it is labelled\n * rather than marked as a diff. The label is text, so it reaches a screen reader as well.\n */\n .input-mark {\n font-style: italic;\n color: var(--neutral-foreground-hint);\n padding-inline-end: calc(var(--design-unit, 4) * 1px);\n }\n\n .row-action p {\n margin-block: calc(var(--design-unit, 4) * 1px);\n }\n\n /* The empty placeholder: a style no row text can take, so a literal \"(blank)\" cannot pass for it. */\n .blank {\n font-style: italic;\n font-weight: 400;\n color: var(--neutral-foreground-hint);\n }\n\n .mark {\n font-weight: 600;\n padding-inline-end: calc(var(--design-unit, 4) * 1px);\n user-select: none;\n }\n\n /* The row's + or − sits beside its checkbox, not on the baseline under it (where − reads as _). */\n td.select {\n white-space: nowrap;\n }\n\n .select rapid-checkbox,\n td.select .mark {\n vertical-align: middle;\n }\n\n /* A gap from the checkbox, so the mark reads as the row's sign rather than part of the box. */\n td.select .mark {\n margin-inline-start: calc(var(--design-unit, 4) * 1.5px);\n }\n\n /* The strike-through belongs to the value, not to its − mark. */\n td.changed .was .mark {\n display: inline-block;\n text-decoration: none;\n }\n\n tr.refused {\n color: var(--neutral-foreground-hint);\n }\n\n /* A refusal is a sentence, and it spans the table: it wraps rather than running off it. */\n .problems {\n color: var(--error-fill-rest, #c00);\n white-space: normal;\n }\n\n /* Wraps, so in a narrow bubble the last button drops to a new line rather than off the edge. */\n .actions {\n display: flex;\n flex-wrap: wrap;\n gap: calc(var(--design-unit, 4) * 2px);\n margin-top: calc(var(--design-unit, 4) * 2px);\n }\n\n /* The change request takes the width the buttons leave it. */\n .change-request {\n flex: 1 1 24ch;\n }\n\n /* The outcome's live region is always there; while the review is open it takes no room. */\n .closed:empty {\n margin: 0;\n }\n\n /* The count sits at the foot of the field, beside it rather than in its way. */\n .remaining {\n align-self: flex-end;\n white-space: nowrap;\n font-size: var(--type-ramp-minus-1-font-size, 0.875em);\n color: var(--neutral-foreground-hint);\n }\n`"
25142
25175
  }
25143
25176
  ],
25144
25177
  "exports": [
@@ -25162,7 +25195,7 @@
25162
25195
  "type": {
25163
25196
  "text": "ViewTemplate<GenesisWriteReview>"
25164
25197
  },
25165
- "default": "html<GenesisWriteReview>`\n ${when(\n (x) => !!x.model,\n html<GenesisWriteReview>`\n ${when(\n (x) => !x.rowActionHeading,\n html<GenesisWriteReview>`\n <p>\n ${(x) => x.model?.op} ${(x) => x.model?.rows.length} row(s) in\n ${(x) => x.model?.resource}. Nothing is written until you choose rows and select Write.\n </p>\n `,\n )}\n ${when(\n (x) => !!x.rowActionHeading,\n html<GenesisWriteReview>`\n <p class=\"row-action-heading\">${(x) => x.rowActionHeading}</p>\n <div class=\"row-action\" id=\"${ROW_ACTION_LINES_ID}\">\n ${repeat(\n (x) => x.rowActionLines,\n html<string>`\n <p>${(x) => x}</p>\n `,\n )}\n </div>\n `,\n )}\n ${when(\n (x) => !!x.customCodeLine,\n html<GenesisWriteReview>`\n <p class=\"custom-code\" id=\"${CUSTOM_CODE_LINE_ID}\">${(x) => x.customCodeLine}</p>\n `,\n )}\n <div class=\"scroller\">\n <table\n aria-label=\"${(x) => x.tableLabel}\"\n aria-describedby=\"${(x) =>\n x.customCodeLine\n ? CUSTOM_CODE_LINE_ID\n : x.rowActionHeading\n ? ROW_ACTION_LINES_ID\n : undefined}\"\n >\n <thead>\n <tr>\n <th>\n <rapid-checkbox\n aria-label=\"Select all rows\"\n :checked=\"${(x) => x.allSelected}\"\n ?disabled=\"${(x) => x.settled || !x.model?.selectable.length}\"\n @change=\"${(x, c) => x.setAll(checkedOf(c.event))}\"\n ></rapid-checkbox>\n </th>\n ${repeat(\n (x) => x.model?.columns ?? [],\n html<ReviewColumn>`\n <th>${(c) => c.label}</th>\n `,\n )}\n </tr>\n </thead>\n <tbody>${repeat((x) => x.model?.rows ?? [], row)}</tbody>\n </table>\n </div>\n <div class=\"actions\">\n ${when(\n (x) => !x.asking,\n html<GenesisWriteReview>`\n <rapid-button\n appearance=\"accent\"\n ?disabled=\"${(x) => !x.writable}\"\n @click=\"${(x) => x.write()}\"\n >\n Write ${(x) => (x.rowsSelected ? `${x.rowsSelected} row(s)` : '')}\n </rapid-button>\n <rapid-button\n class=\"ask\"\n ?disabled=\"${(x) => x.settled}\"\n @click=\"${(x) => x.startAsking()}\"\n >\n Ask for changes\n </rapid-button>\n <rapid-button ?disabled=\"${(x) => x.settled}\" @click=\"${(x) => x.deny()}\">\n Deny\n </rapid-button>\n `,\n )}\n ${when(\n (x) => x.asking,\n html<GenesisWriteReview>`\n <rapid-text-area\n class=\"change-request\"\n :value=\"${(x) => x.changeText}\"\n ?readonly=\"${(x) => x.settled}\"\n maxlength=\"${() => MAX_FEEDBACK_CHARS}\"\n @input=\"${(x, c) => {\n x.setChangeText((c.event.target as HTMLTextAreaElement).value);\n return true;\n }}\"\n >\n What should change?\n </rapid-text-area>\n <span class=\"remaining\">${(x) => x.charactersLeft} characters left</span>\n <rapid-button\n class=\"send\"\n appearance=\"accent\"\n ?disabled=\"${(x) => !x.canSendChanges}\"\n @click=\"${(x) => x.sendChanges()}\"\n >\n Send\n </rapid-button>\n <rapid-button class=\"back\" ?disabled=\"${(x) => x.settled}\" @click=\"${(x) => x.back()}\">\n Back\n </rapid-button>\n `,\n )}\n </div>\n `,\n )}\n ${\n /* A live region, and there from the start: a screen reader announces a change to one it\n already knows, and a region added with its text already in it was not announced at all.\n Empty while the review is open; filled by sayOutcome, which also decides when. Focusable\n from script only, so focus can land on the outcome after an answer. */ ''\n }\n <p class=\"closed\" role=\"status\" tabindex=\"-1\">${(x) => x.announcement}</p>\n`"
25198
+ "default": "html<GenesisWriteReview>`\n ${when(\n (x) => !!x.model,\n html<GenesisWriteReview>`\n ${when(\n (x) => !x.rowActionHeading,\n html<GenesisWriteReview>`\n <p>\n ${(x) => x.model?.op} ${(x) => x.model?.rows.length} row(s) in\n ${(x) => x.model?.resource}. Nothing is written until you choose rows and select Write.\n </p>\n `,\n )}\n ${when(\n (x) => !!x.rowActionHeading,\n html<GenesisWriteReview>`\n <p class=\"row-action-heading\">${(x) => x.rowActionHeading}</p>\n <div class=\"row-action\" id=\"${ROW_ACTION_LINES_ID}\">\n ${repeat(\n (x) => x.rowActionLines,\n html<string>`\n <p>${(x) => x}</p>\n `,\n )}\n </div>\n `,\n )}\n ${when(\n (x) => !!x.customCodeLine,\n html<GenesisWriteReview>`\n <p class=\"custom-code\" id=\"${CUSTOM_CODE_LINE_ID}\">${(x) => x.customCodeLine}</p>\n `,\n )}\n ${\n /* The table's roles are stated, not left to the tags: the stacked layout sets display: block\n on its parts, and a browser then drops their table semantics, so a screen reader would\n hear a run of values with no row or column to put them in. */ ''\n }\n <div class=\"scroller ${(x) => (x.stacked ? 'stacked' : '')}\">\n <table\n role=\"table\"\n aria-label=\"${(x) => x.tableLabel}\"\n aria-describedby=\"${(x) =>\n x.customCodeLine\n ? CUSTOM_CODE_LINE_ID\n : x.rowActionHeading\n ? ROW_ACTION_LINES_ID\n : undefined}\"\n >\n <thead role=\"rowgroup\">\n <tr role=\"row\">\n <th role=\"columnheader\" class=\"select\">\n <rapid-checkbox\n aria-label=\"Select all rows\"\n :checked=\"${(x) => x.allSelected}\"\n ?disabled=\"${(x) => x.settled || !x.model?.selectable.length}\"\n @change=\"${(x, c) => x.setAll(checkedOf(c.event))}\"\n ></rapid-checkbox>\n </th>\n ${repeat(\n (x) => x.model?.columns ?? [],\n html<ReviewColumn>`\n <th role=\"columnheader\">${(c) => c.label}</th>\n `,\n )}\n </tr>\n </thead>\n <tbody role=\"rowgroup\">${repeat((x) => x.model?.rows ?? [], row)}</tbody>\n </table>\n </div>\n <div class=\"actions\">\n ${when(\n (x) => !x.asking,\n html<GenesisWriteReview>`\n <rapid-button\n appearance=\"accent\"\n ?disabled=\"${(x) => !x.writable}\"\n @click=\"${(x) => x.write()}\"\n >\n Write ${(x) => (x.rowsSelected ? `${x.rowsSelected} row(s)` : '')}\n </rapid-button>\n <rapid-button\n class=\"ask\"\n ?disabled=\"${(x) => x.settled}\"\n @click=\"${(x) => x.startAsking()}\"\n >\n Ask for changes\n </rapid-button>\n <rapid-button ?disabled=\"${(x) => x.settled}\" @click=\"${(x) => x.deny()}\">\n Deny\n </rapid-button>\n `,\n )}\n ${when(\n (x) => x.asking,\n html<GenesisWriteReview>`\n <rapid-text-area\n class=\"change-request\"\n :value=\"${(x) => x.changeText}\"\n ?readonly=\"${(x) => x.settled}\"\n maxlength=\"${() => MAX_FEEDBACK_CHARS}\"\n @input=\"${(x, c) => {\n x.setChangeText((c.event.target as HTMLTextAreaElement).value);\n return true;\n }}\"\n >\n What should change?\n </rapid-text-area>\n <span class=\"remaining\">${(x) => x.charactersLeft} characters left</span>\n <rapid-button\n class=\"send\"\n appearance=\"accent\"\n ?disabled=\"${(x) => !x.canSendChanges}\"\n @click=\"${(x) => x.sendChanges()}\"\n >\n Send\n </rapid-button>\n <rapid-button class=\"back\" ?disabled=\"${(x) => x.settled}\" @click=\"${(x) => x.back()}\">\n Back\n </rapid-button>\n `,\n )}\n </div>\n `,\n )}\n ${\n /* A live region, and there from the start: a screen reader announces a change to one it\n already knows, and a region added with its text already in it was not announced at all.\n Empty while the review is open; filled by sayOutcome, which also decides when. Focusable\n from script only, so focus can land on the outcome after an answer. */ ''\n }\n <p class=\"closed\" role=\"status\" tabindex=\"-1\">${(x) => x.announcement}</p>\n`"
25166
25199
  }
25167
25200
  ],
25168
25201
  "exports": [
@@ -25246,6 +25279,33 @@
25246
25279
  "default": "''",
25247
25280
  "description": "What the live region says: the outcome once the review has resolved. See `sayOutcome`."
25248
25281
  },
25282
+ {
25283
+ "kind": "field",
25284
+ "name": "stacked",
25285
+ "type": {
25286
+ "text": "boolean"
25287
+ },
25288
+ "default": "false",
25289
+ "description": "True when the table would not fit the width it has, and each row is laid out as its fields\nstacked label beside value instead."
25290
+ },
25291
+ {
25292
+ "kind": "field",
25293
+ "name": "resizeObserver",
25294
+ "type": {
25295
+ "text": "ResizeObserver | undefined"
25296
+ },
25297
+ "privacy": "private"
25298
+ },
25299
+ {
25300
+ "kind": "field",
25301
+ "name": "tableWidth",
25302
+ "type": {
25303
+ "text": "number"
25304
+ },
25305
+ "privacy": "private",
25306
+ "default": "0",
25307
+ "description": "The table's width when last laid out as a table: what the review needs to stop stacking."
25308
+ },
25249
25309
  {
25250
25310
  "kind": "field",
25251
25311
  "name": "answeredNow",
@@ -25264,6 +25324,17 @@
25264
25324
  "privacy": "private",
25265
25325
  "description": "The answer this element shows while its outcome is still to come, whose `focused` it keeps\ncurrent. The rebuild that brings the outcome gives focus back only if this one held it when\nit was removed: a user who has since moved to the chat input keeps their place."
25266
25326
  },
25327
+ {
25328
+ "kind": "method",
25329
+ "name": "fitLayout",
25330
+ "privacy": "private",
25331
+ "return": {
25332
+ "type": {
25333
+ "text": "void"
25334
+ }
25335
+ },
25336
+ "description": "Stacks the rows when the table is wider than the review, and goes back to the table once the\nreview is as wide as the table was. While stacked there is no table to measure, so the width it\nhad is kept from the last time it was one."
25337
+ },
25267
25338
  {
25268
25339
  "kind": "field",
25269
25340
  "name": "model",