experimental-a2 0.12.0 → 0.14.0

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 (106) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/{actor-DJi3RsNu.d.ts → actor-BfQSE0KC.d.ts} +4 -4
  3. package/dist/{actor-DJi3RsNu.d.ts.map → actor-BfQSE0KC.d.ts.map} +1 -1
  4. package/dist/actor-client.d.ts +1 -1
  5. package/dist/actor-client.js +1 -1
  6. package/dist/actor-react.d.ts +3 -3
  7. package/dist/actor-react.js +2 -2
  8. package/dist/{actor-shared-DI7J5upy.js → actor-shared-B5tJfzt-.js} +2 -2
  9. package/dist/{actor-shared-DI7J5upy.js.map → actor-shared-B5tJfzt-.js.map} +1 -1
  10. package/dist/actor.d.ts +1 -1
  11. package/dist/actor.js +3 -3
  12. package/dist/ai-Cai-lCbj.d.ts +580 -0
  13. package/dist/ai-Cai-lCbj.d.ts.map +1 -0
  14. package/dist/ai-control-CcD4hh3y.js +119 -0
  15. package/dist/ai-control-CcD4hh3y.js.map +1 -0
  16. package/dist/ai-server.d.ts +16 -8
  17. package/dist/ai-server.d.ts.map +1 -1
  18. package/dist/ai-server.js +1322 -475
  19. package/dist/ai-server.js.map +1 -1
  20. package/dist/ai.d.ts +2 -334
  21. package/dist/ai.js +838 -85
  22. package/dist/ai.js.map +1 -1
  23. package/dist/{client-P_NNNRM-.d.ts → client-BAEABRZB.d.ts} +2 -2
  24. package/dist/{client-P_NNNRM-.d.ts.map → client-BAEABRZB.d.ts.map} +1 -1
  25. package/dist/{client-Bf6uSEAk.js → client-BYzHjkwU.js} +21 -6
  26. package/dist/client-BYzHjkwU.js.map +1 -0
  27. package/dist/client.d.ts +1 -1
  28. package/dist/client.js +1 -1
  29. package/dist/{contract-48bUMgcL.js → contract-CKRg_E4q.js} +3 -26
  30. package/dist/contract-CKRg_E4q.js.map +1 -0
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +1 -1
  33. package/dist/react.d.ts +2 -2
  34. package/dist/react.js +1 -1
  35. package/dist/{reducer-DJKWm3cp.d.ts → reducer-BcS9VDKC.d.ts} +4 -1
  36. package/dist/{reducer-DJKWm3cp.d.ts.map → reducer-BcS9VDKC.d.ts.map} +1 -1
  37. package/dist/reducer-DEMjEY_O.js +29 -0
  38. package/dist/reducer-DEMjEY_O.js.map +1 -0
  39. package/dist/scheduler-qstash.d.ts +2 -2
  40. package/dist/scheduler-qstash.js +1 -1
  41. package/dist/scheduler-vercel.d.ts +2 -2
  42. package/dist/scheduler-vercel.js +1 -1
  43. package/dist/{server-DjZZa1wr.d.ts → server-Bp5Nd1pF.d.ts} +3 -3
  44. package/dist/{server-DjZZa1wr.d.ts.map → server-Bp5Nd1pF.d.ts.map} +1 -1
  45. package/dist/{server-BeNADlCI.js → server-CjJSGcF7.js} +4 -3
  46. package/dist/server-CjJSGcF7.js.map +1 -0
  47. package/dist/server.d.ts +3 -3
  48. package/dist/server.js +1 -1
  49. package/dist/{store-DtDOWLSn.d.ts → store-D_yhNdPz.d.ts} +7 -2
  50. package/dist/{store-DtDOWLSn.d.ts.map → store-D_yhNdPz.d.ts.map} +1 -1
  51. package/dist/store-N8PXxDAS.js.map +1 -1
  52. package/dist/store-memory.d.ts +1 -1
  53. package/dist/store-postgres.d.ts +1 -1
  54. package/dist/store-postgres.js +19 -0
  55. package/dist/store-postgres.js.map +1 -1
  56. package/dist/store-redis-http.d.ts +1 -1
  57. package/dist/store-redis-http.js +1 -1
  58. package/dist/{store-redis-notify-BUCyXOn0.js → store-redis-notify-D2EI6gwX.js} +27 -2
  59. package/dist/store-redis-notify-D2EI6gwX.js.map +1 -0
  60. package/dist/store-redis.d.ts +1 -1
  61. package/dist/store-redis.js +1 -1
  62. package/dist/store-sqlite.d.ts +1 -1
  63. package/docs/guides/06-ai-agents.mdx +361 -76
  64. package/docs/reference/01-api.mdx +159 -27
  65. package/examples/playground/app/agent/[agentId]/agent-client.tsx +145 -33
  66. package/examples/playground/app/agent/[agentId]/agent-queue.tsx +289 -0
  67. package/examples/playground/app/agent/[agentId]/compaction/route.ts +14 -0
  68. package/examples/playground/app/agent/[agentId]/compaction-event.tsx +38 -0
  69. package/examples/playground/app/agent/[agentId]/compaction-panel.tsx +294 -0
  70. package/examples/playground/app/agent/compaction-settings.test.ts +144 -0
  71. package/examples/playground/app/agent/compaction-settings.ts +49 -0
  72. package/examples/playground/app/agent/compaction-timeline.test.ts +337 -0
  73. package/examples/playground/app/agent/compaction-timeline.ts +198 -0
  74. package/examples/playground/app/agent/model.ts +56 -1
  75. package/examples/playground/app/agent/server.ts +9 -2
  76. package/examples/playground/app/chat/[chatId]/chat-client.tsx +3 -13
  77. package/examples/playground/app/chat/model.ts +2 -2
  78. package/examples/playground/app/chat/server.ts +24 -17
  79. package/examples/playground/app/globals.css +333 -0
  80. package/examples/playground/package.json +1 -1
  81. package/package.json +1 -1
  82. package/src/ai-client-state.ts +185 -0
  83. package/src/ai-control-server.ts +829 -0
  84. package/src/ai-control-state.ts +152 -0
  85. package/src/ai-control.ts +139 -0
  86. package/src/ai-coordinator.ts +99 -32
  87. package/src/ai-model-metadata.ts +108 -0
  88. package/src/ai-progress-batches.ts +68 -0
  89. package/src/ai-projector.ts +76 -15
  90. package/src/ai-sdk-step.ts +5 -2
  91. package/src/ai-server.ts +920 -638
  92. package/src/ai.ts +650 -110
  93. package/src/client.ts +31 -9
  94. package/src/licenses/Apache-2.0.txt +55 -0
  95. package/src/parse-partial-json.ts +441 -0
  96. package/src/reducer.ts +6 -0
  97. package/src/server.ts +8 -4
  98. package/src/store-postgres.ts +27 -0
  99. package/src/store-redis-core.ts +53 -1
  100. package/src/store-redis-notify.ts +1 -0
  101. package/src/store.ts +6 -0
  102. package/dist/ai.d.ts.map +0 -1
  103. package/dist/client-Bf6uSEAk.js.map +0 -1
  104. package/dist/contract-48bUMgcL.js.map +0 -1
  105. package/dist/server-BeNADlCI.js.map +0 -1
  106. package/dist/store-redis-notify-BUCyXOn0.js.map +0 -1
@@ -1489,6 +1489,160 @@ button.danger {
1489
1489
 
1490
1490
  /* ── durable agent ──────────────────────────────────────────────── */
1491
1491
 
1492
+ .agent-compaction {
1493
+ margin: 1rem 0;
1494
+ padding: 0.75rem 1rem;
1495
+ border: 1px solid var(--line);
1496
+ border-radius: 12px;
1497
+ background: var(--surface);
1498
+ }
1499
+
1500
+ .compaction-marker {
1501
+ display: flex;
1502
+ align-items: center;
1503
+ justify-content: space-between;
1504
+ flex-wrap: wrap;
1505
+ gap: 0.5rem;
1506
+ }
1507
+
1508
+ .agent-compaction > summary {
1509
+ display: flex;
1510
+ align-items: center;
1511
+ gap: 0.5rem;
1512
+ cursor: pointer;
1513
+ list-style: none;
1514
+ }
1515
+
1516
+ .agent-compaction > summary::-webkit-details-marker {
1517
+ display: none;
1518
+ }
1519
+
1520
+ .compaction-chevron {
1521
+ color: var(--muted);
1522
+ }
1523
+
1524
+ .agent-compaction[open] .compaction-chevron {
1525
+ transform: rotate(90deg);
1526
+ }
1527
+
1528
+ .agent-compaction > summary > strong {
1529
+ flex: 1;
1530
+ font-size: 0.9rem;
1531
+ }
1532
+
1533
+ .compaction-controls {
1534
+ margin-top: 0.75rem;
1535
+ padding-top: 0.75rem;
1536
+ border-top: 1px solid var(--line);
1537
+ }
1538
+
1539
+ .agent-compaction code {
1540
+ overflow-wrap: anywhere;
1541
+ }
1542
+
1543
+ .compaction-metrics {
1544
+ display: grid;
1545
+ grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
1546
+ gap: 0.8rem;
1547
+ margin: 1rem 0;
1548
+ }
1549
+
1550
+ .compaction-metrics dt {
1551
+ color: var(--muted);
1552
+ font-size: 0.8rem;
1553
+ }
1554
+
1555
+ .compaction-metrics dd {
1556
+ margin: 0.2rem 0 0;
1557
+ font-weight: 600;
1558
+ font-variant-numeric: tabular-nums;
1559
+ }
1560
+
1561
+ .compaction-form {
1562
+ margin: 0;
1563
+ padding: 0;
1564
+ border: 0;
1565
+ }
1566
+
1567
+ .compaction-form fieldset {
1568
+ margin: 0;
1569
+ padding: 0;
1570
+ border: 0;
1571
+ }
1572
+
1573
+ .compaction-fields {
1574
+ display: grid;
1575
+ grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
1576
+ gap: 0.75rem;
1577
+ }
1578
+
1579
+ .compaction-actions {
1580
+ display: flex;
1581
+ flex-wrap: wrap;
1582
+ gap: 0.5rem;
1583
+ margin-top: 0.75rem;
1584
+ }
1585
+
1586
+ .compaction-history {
1587
+ margin-top: 1rem;
1588
+ padding-top: 0.75rem;
1589
+ border-top: 1px solid var(--line);
1590
+ }
1591
+
1592
+ .compaction-history summary {
1593
+ cursor: pointer;
1594
+ font-size: 0.9rem;
1595
+ }
1596
+
1597
+ .compaction-history ol {
1598
+ padding: 0;
1599
+ list-style: none;
1600
+ }
1601
+
1602
+ .compaction-history li + li {
1603
+ border-top: 1px solid var(--line);
1604
+ margin-top: 0.75rem;
1605
+ padding-top: 0.75rem;
1606
+ }
1607
+
1608
+ .compaction-marker {
1609
+ font-size: 0.85rem;
1610
+ }
1611
+
1612
+ .compaction-marker time {
1613
+ color: var(--muted);
1614
+ }
1615
+
1616
+ .compaction-history pre,
1617
+ .agent-compaction-event pre {
1618
+ white-space: pre-wrap;
1619
+ overflow-wrap: anywhere;
1620
+ max-height: 20rem;
1621
+ overflow: auto;
1622
+ }
1623
+
1624
+ .agent-compaction-event {
1625
+ padding: 0.65rem 0.85rem;
1626
+ border: 1px dashed var(--line);
1627
+ border-radius: 9px;
1628
+ background: var(--code-bg);
1629
+ }
1630
+
1631
+ .agent-compaction-event summary {
1632
+ cursor: pointer;
1633
+ font-size: 0.85rem;
1634
+ color: var(--muted);
1635
+ }
1636
+
1637
+ .agent-compaction-event summary > span {
1638
+ font-weight: 600;
1639
+ }
1640
+
1641
+ .agent-compaction-event time {
1642
+ display: inline-block;
1643
+ margin-left: 0.75rem;
1644
+ }
1645
+
1492
1646
  .agent-conversation {
1493
1647
  display: grid;
1494
1648
  overflow: hidden;
@@ -1645,6 +1799,185 @@ button.danger {
1645
1799
  flex: 0 0 auto;
1646
1800
  }
1647
1801
 
1802
+ .agent-queue {
1803
+ margin: 0 1rem 0.85rem;
1804
+ border: 1px solid var(--line);
1805
+ border-radius: 9px;
1806
+ background: var(--bg);
1807
+ overflow: hidden;
1808
+ }
1809
+
1810
+ .agent-queue-header {
1811
+ display: flex;
1812
+ align-items: center;
1813
+ justify-content: space-between;
1814
+ gap: 0.75rem;
1815
+ padding: 0.55rem 0.8rem;
1816
+ border-bottom: 1px solid var(--line);
1817
+ }
1818
+
1819
+ .agent-queue-header h3 {
1820
+ display: flex;
1821
+ align-items: center;
1822
+ gap: 0.45rem;
1823
+ margin: 0;
1824
+ color: var(--muted);
1825
+ font-size: 0.75rem;
1826
+ font-weight: 600;
1827
+ }
1828
+
1829
+ .agent-queue-header h3 span {
1830
+ min-width: 1.2rem;
1831
+ padding: 0 0.3rem;
1832
+ border-radius: 4px;
1833
+ background: var(--line);
1834
+ text-align: center;
1835
+ font-size: 0.68rem;
1836
+ font-variant-numeric: tabular-nums;
1837
+ }
1838
+
1839
+ .agent-queue-status {
1840
+ color: var(--muted);
1841
+ font-size: 0.7rem;
1842
+ }
1843
+
1844
+ .agent-queue-status.paused {
1845
+ color: #885b12;
1846
+ }
1847
+
1848
+ .agent-queue-list {
1849
+ max-height: 17rem;
1850
+ overflow-y: auto;
1851
+ overscroll-behavior: contain;
1852
+ list-style: none;
1853
+ margin: 0;
1854
+ padding: 0.15rem 0;
1855
+ }
1856
+
1857
+ .agent-queue-item + .agent-queue-item {
1858
+ border-top: 1px solid var(--line);
1859
+ }
1860
+
1861
+ .agent-queue-row {
1862
+ display: grid;
1863
+ grid-template-columns: 1.25rem minmax(0, 1fr) auto;
1864
+ align-items: center;
1865
+ gap: 0.5rem;
1866
+ min-height: 2.7rem;
1867
+ padding: 0.25rem 0.55rem 0.25rem 0.8rem;
1868
+ }
1869
+
1870
+ .agent-queue-number {
1871
+ color: var(--muted);
1872
+ font-size: 0.7rem;
1873
+ font-variant-numeric: tabular-nums;
1874
+ }
1875
+
1876
+ .agent-queue-text {
1877
+ margin: 0;
1878
+ overflow: hidden;
1879
+ white-space: nowrap;
1880
+ text-overflow: ellipsis;
1881
+ font-size: 0.83rem;
1882
+ }
1883
+
1884
+ .agent-queue-actions {
1885
+ display: flex;
1886
+ gap: 0.1rem;
1887
+ }
1888
+
1889
+ .agent-queue-actions button {
1890
+ display: grid;
1891
+ place-items: center;
1892
+ width: 1.9rem;
1893
+ height: 1.9rem;
1894
+ padding: 0;
1895
+ border: 0;
1896
+ border-radius: 5px;
1897
+ background: transparent;
1898
+ color: var(--muted);
1899
+ }
1900
+
1901
+ .agent-queue-actions button:hover:not(:disabled),
1902
+ .agent-queue-actions button[aria-expanded='true'] {
1903
+ background: var(--line);
1904
+ color: var(--ink);
1905
+ filter: none;
1906
+ }
1907
+
1908
+ .agent-queue-actions button:disabled {
1909
+ opacity: 0.22;
1910
+ }
1911
+
1912
+ .agent-queue-actions .agent-queue-send {
1913
+ color: var(--accent);
1914
+ }
1915
+
1916
+ .agent-queue-actions .agent-queue-remove:hover:not(:disabled) {
1917
+ background: #f8e8e5;
1918
+ color: var(--danger);
1919
+ }
1920
+
1921
+ .agent-queue-error {
1922
+ margin: 0;
1923
+ padding: 0 0.75rem 0.65rem 2.55rem;
1924
+ font-size: 0.75rem;
1925
+ }
1926
+
1927
+ .agent-queue-item.editing {
1928
+ background: var(--surface);
1929
+ }
1930
+
1931
+ .agent-queue-editor {
1932
+ gap: 0.45rem;
1933
+ margin: 0;
1934
+ padding: 0 0.75rem 0.65rem 2.55rem;
1935
+ border: 0;
1936
+ border-radius: 0;
1937
+ }
1938
+
1939
+ .agent-queue-editor textarea {
1940
+ width: 100%;
1941
+ min-width: 0;
1942
+ resize: vertical;
1943
+ font-size: 0.83rem;
1944
+ line-height: 1.5;
1945
+ }
1946
+
1947
+ .agent-queue-editor-actions {
1948
+ display: flex;
1949
+ align-items: center;
1950
+ justify-content: flex-end;
1951
+ gap: 0.35rem;
1952
+ }
1953
+
1954
+ .agent-queue-editor-actions span {
1955
+ margin-right: auto;
1956
+ color: var(--muted);
1957
+ font-size: 0.65rem;
1958
+ }
1959
+
1960
+ .agent-queue-editor-actions button {
1961
+ padding: 0.3rem 0.6rem;
1962
+ font-size: 0.72rem;
1963
+ }
1964
+
1965
+ @media (pointer: coarse) {
1966
+ .agent-queue-actions button {
1967
+ width: 2.25rem;
1968
+ height: 2.5rem;
1969
+ }
1970
+ }
1971
+
1972
+ @media (max-width: 420px) {
1973
+ .agent-queue-editor {
1974
+ padding-left: 0.75rem;
1975
+ }
1976
+ .agent-queue-editor-actions span {
1977
+ display: none;
1978
+ }
1979
+ }
1980
+
1648
1981
  .agent-form {
1649
1982
  margin: 0;
1650
1983
  padding: 1rem;
@@ -22,7 +22,7 @@
22
22
  "@vercel/sandbox": "^3.0.0",
23
23
  "ai": "^7.0.58",
24
24
  "codemirror": "^6.0.2",
25
- "experimental-a2": "0.12.0",
25
+ "experimental-a2": "0.14.0",
26
26
  "ioredis": "^5.9.0",
27
27
  "next": "^16.3.0",
28
28
  "pg": "^8.16.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "experimental-a2",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Durable sync and reactions for things with a lifecycle: one event log, derived state, and live client per session.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -0,0 +1,185 @@
1
+ import type { UIMessage } from 'ai'
2
+ import type { AIState } from './ai.ts'
3
+ import type { ControlCommand, InboxItem } from './ai-control.ts'
4
+
5
+ export type QueueCommand<M extends UIMessage> = Extract<
6
+ ControlCommand<M>,
7
+ {
8
+ action:
9
+ | 'send'
10
+ | 'edit'
11
+ | 'move'
12
+ | 'remove'
13
+ | 'send-now'
14
+ | 'steer'
15
+ | 'pause'
16
+ | 'resume'
17
+ }
18
+ >
19
+ export type PendingQueueCommand<M extends UIMessage> = {
20
+ commandId: string
21
+ command: QueueCommand<M>
22
+ }
23
+
24
+ export const isQueueCommand = <M extends UIMessage>(
25
+ command: ControlCommand<M>,
26
+ ): command is QueueCommand<M> =>
27
+ command.action === 'send' ||
28
+ command.action === 'edit' ||
29
+ command.action === 'move' ||
30
+ command.action === 'remove' ||
31
+ command.action === 'send-now' ||
32
+ command.action === 'steer' ||
33
+ command.action === 'pause' ||
34
+ command.action === 'resume'
35
+
36
+ const moveItem = <M extends UIMessage>({
37
+ items,
38
+ inputId,
39
+ beforeId,
40
+ }: {
41
+ items: InboxItem<M>[]
42
+ inputId: string
43
+ beforeId: string | null
44
+ }): InboxItem<M>[] => {
45
+ const from = items.findIndex((item) => item.id === inputId)
46
+ if (
47
+ from < 0 ||
48
+ inputId === beforeId ||
49
+ (beforeId !== null && !items.some((item) => item.id === beforeId))
50
+ )
51
+ return items
52
+ const next = [...items]
53
+ const [item] = next.splice(from, 1)
54
+ const to =
55
+ beforeId === null
56
+ ? next.length
57
+ : next.findIndex((entry) => entry.id === beforeId)
58
+ next.splice(to, 0, item!)
59
+ return next
60
+ }
61
+
62
+ export function projectAIClientState<M extends UIMessage>(
63
+ state: AIState<M>,
64
+ ): AIState<M> {
65
+ const pending = state.pendingQueueCommands ?? []
66
+ if (state.status === 'closed') return state
67
+ if (
68
+ pending.length === 0 &&
69
+ !state.inbox.items.some((item) => item.afterStepOf !== undefined)
70
+ )
71
+ return state
72
+ let messages = state.messages
73
+ let { items, paused } = state.inbox
74
+ let turnId = state.active?.turnId ?? null
75
+ let starting = false
76
+ let suspended =
77
+ state.active?.phase === 'paused' || state.active?.phase === 'pausing'
78
+ let messageIds: Set<string> | undefined
79
+ const show = (message: M): void => {
80
+ messageIds ??= new Set(messages.map((item) => item.id))
81
+ if (messageIds.has(message.id)) return
82
+ if (messages === state.messages) messages = state.messages.slice()
83
+ messages.push(message)
84
+ messageIds.add(message.id)
85
+ }
86
+ const admit = (): void => {
87
+ if (turnId !== null || paused || items.length === 0) return
88
+ let count = 0
89
+ for (const item of items) {
90
+ count += 1
91
+ show(item.message)
92
+ if (item.generate) {
93
+ turnId = item.id
94
+ starting = true
95
+ suspended = false
96
+ break
97
+ }
98
+ }
99
+ if (count > 0) items = items.slice(count)
100
+ }
101
+ for (const { command } of pending) {
102
+ switch (command.action) {
103
+ case 'send':
104
+ case 'steer': {
105
+ if (
106
+ items.some((item) => item.id === command.message.id) ||
107
+ turnId === command.message.id
108
+ )
109
+ break
110
+ const item = {
111
+ ...(command.action === 'steer'
112
+ ? { afterStepOf: command.turnId }
113
+ : {}),
114
+ id: command.message.id,
115
+ revision: 0,
116
+ message: command.message,
117
+ generate:
118
+ command.message.role === 'user' &&
119
+ (command.action === 'steer' || command.generate !== false),
120
+ }
121
+ items = command.action === 'steer' ? [item, ...items] : [...items, item]
122
+ break
123
+ }
124
+ case 'edit':
125
+ items = items.map((item) =>
126
+ item.id === command.message.id &&
127
+ item.revision === command.expectedRevision &&
128
+ item.message.role === command.message.role
129
+ ? { ...item, message: command.message }
130
+ : item,
131
+ )
132
+ break
133
+ case 'move':
134
+ items = moveItem({
135
+ items,
136
+ inputId: command.inputId,
137
+ beforeId: command.beforeId,
138
+ })
139
+ break
140
+ case 'remove':
141
+ items = items.filter((item) => item.id !== command.inputId)
142
+ break
143
+ case 'send-now': {
144
+ if (turnId !== command.turnId) break
145
+ const selected = items.find((item) => item.id === command.inputId)
146
+ if (!selected || selected.message.role !== 'user') break
147
+ items = items.map((item) =>
148
+ item.id === selected.id
149
+ ? {
150
+ ...item,
151
+ generate: true,
152
+ ...(turnId === null ? {} : { afterStepOf: turnId }),
153
+ }
154
+ : item,
155
+ )
156
+ items = moveItem({
157
+ items,
158
+ inputId: command.inputId,
159
+ beforeId: items[0]?.id ?? null,
160
+ })
161
+ break
162
+ }
163
+ case 'pause':
164
+ paused = true
165
+ if (command.when === 'now') suspended = true
166
+ break
167
+ case 'resume':
168
+ paused = false
169
+ suspended = false
170
+ break
171
+ }
172
+ admit()
173
+ }
174
+ items = items.filter((item) => {
175
+ if (item.afterStepOf === undefined) return true
176
+ show(item.message)
177
+ return false
178
+ })
179
+ return {
180
+ ...state,
181
+ messages,
182
+ inbox: { items, paused },
183
+ starting: starting && !suspended,
184
+ }
185
+ }