@assistant-ui/core 0.3.4 → 0.3.6

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 (147) hide show
  1. package/dist/index.d.ts +3 -3
  2. package/dist/index.js.map +1 -1
  3. package/dist/internal.js +1 -1
  4. package/dist/react/AssistantProvider.d.ts +3 -2
  5. package/dist/react/AssistantProvider.d.ts.map +1 -1
  6. package/dist/react/AssistantProvider.js +19 -26
  7. package/dist/react/AssistantProvider.js.map +1 -1
  8. package/dist/react/AssistantRuntimeProvider.d.ts +7 -2
  9. package/dist/react/AssistantRuntimeProvider.d.ts.map +1 -1
  10. package/dist/react/AssistantRuntimeProvider.js +9 -7
  11. package/dist/react/AssistantRuntimeProvider.js.map +1 -1
  12. package/dist/react/providers/AttachmentByIndexProvider.d.ts.map +1 -1
  13. package/dist/react/providers/AttachmentByIndexProvider.js +33 -39
  14. package/dist/react/providers/AttachmentByIndexProvider.js.map +1 -1
  15. package/dist/react/providers/ChainOfThoughtByIndicesProvider.d.ts.map +1 -1
  16. package/dist/react/providers/ChainOfThoughtByIndicesProvider.js +15 -20
  17. package/dist/react/providers/ChainOfThoughtByIndicesProvider.js.map +1 -1
  18. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js +17 -20
  19. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js.map +1 -1
  20. package/dist/react/providers/MessageByIdProvider.js +28 -38
  21. package/dist/react/providers/MessageByIdProvider.js.map +1 -1
  22. package/dist/react/providers/MessageByIndexProvider.js +28 -38
  23. package/dist/react/providers/MessageByIndexProvider.js.map +1 -1
  24. package/dist/react/providers/PartByIndexProvider.js +17 -20
  25. package/dist/react/providers/PartByIndexProvider.js.map +1 -1
  26. package/dist/react/providers/QueueItemByIndexProvider.js +21 -21
  27. package/dist/react/providers/QueueItemByIndexProvider.js.map +1 -1
  28. package/dist/react/providers/ReadonlyThreadProvider.js +24 -32
  29. package/dist/react/providers/ReadonlyThreadProvider.js.map +1 -1
  30. package/dist/react/providers/SuggestionByIndexProvider.js +17 -20
  31. package/dist/react/providers/SuggestionByIndexProvider.js.map +1 -1
  32. package/dist/react/providers/TextMessagePartProvider.d.ts.map +1 -1
  33. package/dist/react/providers/TextMessagePartProvider.js +16 -19
  34. package/dist/react/providers/TextMessagePartProvider.js.map +1 -1
  35. package/dist/react/providers/ThreadListItemByIndexProvider.js +17 -20
  36. package/dist/react/providers/ThreadListItemByIndexProvider.js.map +1 -1
  37. package/dist/react/providers/ThreadListItemRuntimeProvider.js +15 -18
  38. package/dist/react/providers/ThreadListItemRuntimeProvider.js.map +1 -1
  39. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +7 -3
  40. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  41. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +5 -2
  42. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  43. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +4 -3
  44. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  45. package/dist/react/runtimes/useLocalRuntime.d.ts +3 -1
  46. package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
  47. package/dist/react/runtimes/useLocalRuntime.js +4 -2
  48. package/dist/react/runtimes/useLocalRuntime.js.map +1 -1
  49. package/dist/runtime/api/composer-runtime.d.ts +5 -1
  50. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  51. package/dist/runtime/api/composer-runtime.js +8 -1
  52. package/dist/runtime/api/composer-runtime.js.map +1 -1
  53. package/dist/runtime/api/message-runtime.js +1 -1
  54. package/dist/runtime/api/message-runtime.js.map +1 -1
  55. package/dist/runtime/api/thread-runtime.d.ts +4 -2
  56. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  57. package/dist/runtime/base/base-composer-runtime-core.d.ts +2 -1
  58. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  59. package/dist/runtime/base/base-composer-runtime-core.js +1 -1
  60. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  61. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +3 -1
  62. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  63. package/dist/runtime/base/default-thread-composer-runtime-core.js +14 -3
  64. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  65. package/dist/runtime/interfaces/composer-runtime-core.d.ts +2 -1
  66. package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
  67. package/dist/runtime/interfaces/thread-runtime-core.d.ts +3 -1
  68. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  69. package/dist/runtime/queue/external-thread-queue-adapter.d.ts +19 -6
  70. package/dist/runtime/queue/external-thread-queue-adapter.d.ts.map +1 -1
  71. package/dist/runtime/queue/message-queue.d.ts +10 -1
  72. package/dist/runtime/queue/message-queue.d.ts.map +1 -1
  73. package/dist/runtime/queue/message-queue.js +138 -36
  74. package/dist/runtime/queue/message-queue.js.map +1 -1
  75. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  76. package/dist/runtime/utils/thread-message-like.js +2 -1
  77. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  78. package/dist/runtimes/external-store/external-store-adapter.d.ts +1 -1
  79. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +3 -1
  80. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  81. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +7 -6
  82. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  83. package/dist/runtimes/local/local-runtime-options.d.ts +13 -0
  84. package/dist/runtimes/local/local-runtime-options.d.ts.map +1 -1
  85. package/dist/runtimes/local/local-thread-runtime-core.d.ts +5 -1
  86. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  87. package/dist/runtimes/local/local-thread-runtime-core.js +30 -14
  88. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  89. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +1 -1
  90. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +1 -1
  91. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  92. package/dist/runtimes/remote-thread-list/empty-thread-core.js +1 -1
  93. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  94. package/dist/runtimes/remote-thread-list/types.d.ts +6 -3
  95. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  96. package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
  97. package/dist/store/runtime-clients/composer-runtime-client.js +11 -4
  98. package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
  99. package/dist/store/scopes/composer.d.ts +7 -3
  100. package/dist/store/scopes/composer.d.ts.map +1 -1
  101. package/dist/store/scopes/queue-item.d.ts +10 -0
  102. package/dist/store/scopes/queue-item.d.ts.map +1 -1
  103. package/dist/store/scopes/queue-item.js.map +1 -1
  104. package/package.json +6 -6
  105. package/src/index.ts +5 -1
  106. package/src/react/AssistantProvider.tsx +20 -18
  107. package/src/react/AssistantRuntimeProvider.test.tsx +55 -1
  108. package/src/react/AssistantRuntimeProvider.tsx +12 -2
  109. package/src/react/providers/AttachmentByIndexProvider.tsx +15 -7
  110. package/src/react/providers/ChainOfThoughtByIndicesProvider.tsx +12 -4
  111. package/src/react/providers/ChainOfThoughtPartByIndexProvider.tsx +8 -4
  112. package/src/react/providers/MessageByIdProvider.tsx +8 -4
  113. package/src/react/providers/MessageByIndexProvider.tsx +8 -4
  114. package/src/react/providers/PartByIndexProvider.tsx +8 -4
  115. package/src/react/providers/QueueItemByIndexProvider.tsx +9 -5
  116. package/src/react/providers/ReadonlyThreadProvider.tsx +9 -4
  117. package/src/react/providers/SuggestionByIndexProvider.tsx +8 -4
  118. package/src/react/providers/TextMessagePartProvider.tsx +13 -4
  119. package/src/react/providers/ThreadListItemByIndexProvider.tsx +8 -4
  120. package/src/react/providers/ThreadListItemRuntimeProvider.tsx +8 -4
  121. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +23 -5
  122. package/src/react/runtimes/useLocalRuntime.ts +4 -0
  123. package/src/runtime/api/composer-runtime.ts +11 -2
  124. package/src/runtime/api/message-runtime.test.ts +25 -0
  125. package/src/runtime/api/message-runtime.ts +1 -1
  126. package/src/runtime/base/base-composer-runtime-core.ts +5 -1
  127. package/src/runtime/base/default-thread-composer-runtime-core.ts +27 -3
  128. package/src/runtime/interfaces/composer-runtime-core.ts +2 -1
  129. package/src/runtime/interfaces/thread-runtime-core.ts +3 -1
  130. package/src/runtime/queue/external-thread-queue-adapter.ts +19 -3
  131. package/src/runtime/queue/message-queue.ts +200 -38
  132. package/src/runtime/utils/thread-message-like.ts +2 -4
  133. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +10 -8
  134. package/src/runtimes/local/local-runtime-options.ts +15 -0
  135. package/src/runtimes/local/local-thread-runtime-core.test.ts +43 -0
  136. package/src/runtimes/local/local-thread-runtime-core.ts +48 -13
  137. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +1 -1
  138. package/src/runtimes/remote-thread-list/empty-thread-core.ts +1 -1
  139. package/src/runtimes/remote-thread-list/types.ts +9 -2
  140. package/src/store/runtime-clients/composer-runtime-client.ts +13 -5
  141. package/src/store/scopes/composer.ts +6 -4
  142. package/src/store/scopes/queue-item.ts +8 -1
  143. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-order.test.ts +31 -0
  144. package/src/tests/external-store-thread-runtime-core.test.ts +56 -13
  145. package/src/tests/framework-neutral-boundary.test.ts +221 -0
  146. package/src/tests/message-queue.test.ts +494 -34
  147. package/src/tests/thread-message-like.test.ts +66 -0
@@ -0,0 +1,221 @@
1
+ /// <reference types="node" />
2
+ import { describe, expect, it } from "vitest";
3
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
4
+ import { dirname, join, relative, resolve } from "node:path";
5
+
6
+ const SRC_DIR = resolve(__dirname, "..");
7
+
8
+ const FORBIDDEN_MODULES = new Set([
9
+ "react",
10
+ "react/jsx-runtime",
11
+ "@assistant-ui/store",
12
+ "@assistant-ui/tap",
13
+ ]);
14
+
15
+ const STORE_ALLOWED_REACT_NAMES = new Set([
16
+ "useState",
17
+ "useReducer",
18
+ "useRef",
19
+ "useMemo",
20
+ "useCallback",
21
+ "useEffect",
22
+ "useLayoutEffect",
23
+ "useInsertionEffect",
24
+ "useEffectEvent",
25
+ "useSyncExternalStore",
26
+ "useDebugValue",
27
+ "use",
28
+ "useContext",
29
+ "createContext",
30
+ ]);
31
+
32
+ const IMPORT_RE =
33
+ /(?:import|export)\s+(?:type\s+)?(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)(?:\s*,\s*(?:\{[^}]*\}|\*\s+as\s+\w+|\w+))*\s+from\s+)?["']([^"']+)["']/g;
34
+
35
+ const SIDE_EFFECT_IMPORT_RE = /import\s+["']([^"']+)["']/g;
36
+
37
+ const EXPORT_STAR_RE = /export\s+\*\s+from\s+["']([^"']+)["']/g;
38
+
39
+ const DYNAMIC_IMPORT_RE = /\b(?:import|require)\s*\(\s*["']([^"']+)["']\s*\)/g;
40
+
41
+ const FROM_REACT_RE =
42
+ /(?:import|export)\s+(?:type\s+)?([\s\S]*?)\s+from\s+["']react["']/g;
43
+
44
+ function resolveRelative(fromFile: string, spec: string): string | null {
45
+ if (!spec.startsWith(".")) return null;
46
+ const base = resolve(dirname(fromFile), spec);
47
+ const candidates = [
48
+ base,
49
+ `${base}.ts`,
50
+ `${base}.tsx`,
51
+ join(base, "index.ts"),
52
+ join(base, "index.tsx"),
53
+ ];
54
+ for (const candidate of candidates) {
55
+ if (existsSync(candidate) && statSync(candidate).isFile()) {
56
+ return candidate;
57
+ }
58
+ }
59
+ return null;
60
+ }
61
+
62
+ function collectImports(content: string): string[] {
63
+ const specs: string[] = [];
64
+ for (const re of [
65
+ IMPORT_RE,
66
+ SIDE_EFFECT_IMPORT_RE,
67
+ EXPORT_STAR_RE,
68
+ DYNAMIC_IMPORT_RE,
69
+ ]) {
70
+ re.lastIndex = 0;
71
+ let match: RegExpExecArray | null;
72
+ while ((match = re.exec(content)) !== null) {
73
+ specs.push(match[1]!);
74
+ }
75
+ }
76
+ return specs;
77
+ }
78
+
79
+ function walkFrom(entry: string): { forbidden: string[]; jsxFiles: string[] } {
80
+ const visited = new Set<string>();
81
+ const queue = [entry];
82
+ const forbidden: string[] = [];
83
+
84
+ while (queue.length > 0) {
85
+ const file = queue.pop()!;
86
+ if (visited.has(file)) continue;
87
+ visited.add(file);
88
+
89
+ const content = readFileSync(file, "utf-8");
90
+ const specs = collectImports(content);
91
+
92
+ for (const spec of specs) {
93
+ if (FORBIDDEN_MODULES.has(spec)) {
94
+ forbidden.push(`${relative(SRC_DIR, file)} imports "${spec}"`);
95
+ continue;
96
+ }
97
+ const resolved = resolveRelative(file, spec);
98
+ if (resolved && !visited.has(resolved)) {
99
+ queue.push(resolved);
100
+ }
101
+ }
102
+ }
103
+
104
+ const jsxFiles = [...visited]
105
+ .filter((file) => file.endsWith(".tsx"))
106
+ .map((file) => relative(SRC_DIR, file));
107
+
108
+ return { forbidden, jsxFiles };
109
+ }
110
+
111
+ function findFiles(dir: string, ext: string[]): string[] {
112
+ const results: string[] = [];
113
+ for (const entry of readdirSync(dir)) {
114
+ const full = join(dir, entry);
115
+ if (statSync(full).isDirectory()) {
116
+ results.push(...findFiles(full, ext));
117
+ } else if (ext.some((e) => full.endsWith(e))) {
118
+ results.push(full);
119
+ }
120
+ }
121
+ return results;
122
+ }
123
+
124
+ function nonTypeImportNames(clause: string): string[] {
125
+ const names: string[] = [];
126
+ const trimmed = clause.trim();
127
+ if (trimmed.startsWith("type ")) return names;
128
+ if (/^\*\s+as\s+\w+$/.test(trimmed)) return names;
129
+
130
+ const defaultAndNamed = trimmed.match(/^(\w+)\s*,\s*\{([\s\S]*)\}$/);
131
+ const namedOnly = trimmed.match(/^\{([\s\S]*)\}$/);
132
+ const defaultOnly = trimmed.match(/^(\w+)$/);
133
+
134
+ let namedBody = "";
135
+ if (defaultAndNamed) {
136
+ names.push(defaultAndNamed[1]!);
137
+ namedBody = defaultAndNamed[2]!;
138
+ } else if (namedOnly) {
139
+ namedBody = namedOnly[1]!;
140
+ } else if (defaultOnly) {
141
+ names.push(defaultOnly[1]!);
142
+ return names;
143
+ } else {
144
+ return names;
145
+ }
146
+
147
+ for (const part of namedBody.split(",")) {
148
+ const p = part.trim();
149
+ if (!p || p.startsWith("type ")) continue;
150
+ const asMatch = p.match(/^(\w+)(?:\s+as\s+\w+)?$/);
151
+ if (asMatch) names.push(asMatch[1]!);
152
+ }
153
+ return names;
154
+ }
155
+
156
+ describe("framework neutral boundary", () => {
157
+ it("the default entry graph must not import react, react/jsx-runtime, @assistant-ui/tap, or @assistant-ui/store", () => {
158
+ const { forbidden, jsxFiles } = walkFrom(resolve(SRC_DIR, "index.ts"));
159
+ expect(
160
+ forbidden,
161
+ `The default entry must stay loadable without react, @assistant-ui/tap, or @assistant-ui/store installed.\n` +
162
+ `These modules in the src/index.ts graph import a forbidden package:\n` +
163
+ forbidden.map((f) => ` - ${f}`).join("\n"),
164
+ ).toEqual([]);
165
+ expect(
166
+ jsxFiles,
167
+ `The JSX transform injects react/jsx-runtime at build time, so the default entry graph must not contain .tsx files:\n` +
168
+ jsxFiles.map((f) => ` - ${f}`).join("\n"),
169
+ ).toEqual([]);
170
+ });
171
+
172
+ it("the internal entry graph must not import react, react/jsx-runtime, @assistant-ui/tap, or @assistant-ui/store", () => {
173
+ const { forbidden, jsxFiles } = walkFrom(resolve(SRC_DIR, "internal.ts"));
174
+ expect(
175
+ forbidden,
176
+ "The internal entry must stay loadable without react, react/jsx-runtime, @assistant-ui/tap, or @assistant-ui/store installed.\nViolations:\n" +
177
+ forbidden.map((f) => ` - ${f}`).join("\n"),
178
+ ).toEqual([]);
179
+ expect(
180
+ jsxFiles,
181
+ `The JSX transform injects react/jsx-runtime at build time, so the internal entry graph must not contain .tsx files:\n` +
182
+ jsxFiles.map((f) => ` - ${f}`).join("\n"),
183
+ ).toEqual([]);
184
+ });
185
+
186
+ it("src/store may only pull react names the tap shim dispatches", () => {
187
+ const storeDir = resolve(SRC_DIR, "store");
188
+ const files = findFiles(storeDir, [".ts"]).filter(
189
+ (f) => !f.includes(".test."),
190
+ );
191
+ const violations: string[] = [];
192
+
193
+ for (const file of files) {
194
+ const content = readFileSync(file, "utf-8");
195
+ FROM_REACT_RE.lastIndex = 0;
196
+ let match: RegExpExecArray | null;
197
+ while ((match = FROM_REACT_RE.exec(content)) !== null) {
198
+ if (/^(?:import|export)\s+type\b/.test(match[0]!)) continue;
199
+ const clause = match[1]!;
200
+ if (clause.trimStart().startsWith("type ")) continue;
201
+ for (const name of nonTypeImportNames(clause)) {
202
+ if (!STORE_ALLOWED_REACT_NAMES.has(name)) {
203
+ violations.push(
204
+ `${relative(SRC_DIR, file)} imports "${name}" from "react"`,
205
+ );
206
+ }
207
+ }
208
+ }
209
+ }
210
+
211
+ expect(
212
+ violations,
213
+ `src/store may only use react names the tap shim dispatches ` +
214
+ `(useState, useReducer, useRef, useMemo, useCallback, useEffect, useLayoutEffect, ` +
215
+ `useInsertionEffect, useEffectEvent, useSyncExternalStore, useDebugValue, use, ` +
216
+ `useContext, createContext).\n` +
217
+ `Violations:\n` +
218
+ violations.map((f) => ` - ${f}`).join("\n"),
219
+ ).toEqual([]);
220
+ });
221
+ });