@dxos/assistant 0.8.2-main.fbd8ed0 → 0.8.2-staging.4d6ad0f

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 (289) hide show
  1. package/dist/lib/browser/index.mjs +1983 -64
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +1976 -63
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +1984 -64
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/{src/bin → bin}/chat.d.ts.map +1 -1
  11. package/dist/types/src/blueprint/blueprint.d.ts +79 -0
  12. package/dist/types/src/blueprint/blueprint.d.ts.map +1 -0
  13. package/dist/types/src/blueprint/blueprint.test.d.ts +2 -0
  14. package/dist/types/src/blueprint/blueprint.test.d.ts.map +1 -0
  15. package/dist/types/src/blueprint/index.d.ts +4 -0
  16. package/dist/types/src/blueprint/index.d.ts.map +1 -0
  17. package/dist/types/src/blueprint/logger.d.ts +3 -0
  18. package/dist/types/src/blueprint/logger.d.ts.map +1 -0
  19. package/dist/types/src/{ai-service/parser.d.ts → blueprint/machine.d.ts} +46 -68
  20. package/dist/types/src/blueprint/machine.d.ts.map +1 -0
  21. package/dist/types/src/blueprint/test-data.d.ts +3 -0
  22. package/dist/types/src/blueprint/test-data.d.ts.map +1 -0
  23. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts +4 -0
  24. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +1 -0
  25. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts +2 -0
  26. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts.map +1 -0
  27. package/dist/types/src/extraction/extraction-llm-function/index.d.ts +2 -0
  28. package/dist/types/src/extraction/extraction-llm-function/index.d.ts.map +1 -0
  29. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +210 -0
  30. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -0
  31. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts +2 -0
  32. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts.map +1 -0
  33. package/dist/types/src/extraction/extraction-ner-function/index.d.ts +3 -0
  34. package/dist/types/src/extraction/extraction-ner-function/index.d.ts.map +1 -0
  35. package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts +14 -0
  36. package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts.map +1 -0
  37. package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.test.d.ts +2 -0
  38. package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.test.d.ts.map +1 -0
  39. package/dist/types/src/extraction/extraction.d.ts +242 -0
  40. package/dist/types/src/extraction/extraction.d.ts.map +1 -0
  41. package/dist/types/src/extraction/index.d.ts +5 -0
  42. package/dist/types/src/extraction/index.d.ts.map +1 -0
  43. package/dist/types/src/extraction/quotes.d.ts +15 -0
  44. package/dist/types/src/extraction/quotes.d.ts.map +1 -0
  45. package/dist/types/src/extraction/quotes.test.d.ts +2 -0
  46. package/dist/types/src/extraction/quotes.test.d.ts.map +1 -0
  47. package/dist/types/src/index.d.ts +4 -2
  48. package/dist/types/src/index.d.ts.map +1 -1
  49. package/dist/types/src/research/exa.d.ts +7 -0
  50. package/dist/types/src/research/exa.d.ts.map +1 -0
  51. package/dist/types/src/research/graph.d.ts +39 -0
  52. package/dist/types/src/research/graph.d.ts.map +1 -0
  53. package/dist/types/src/research/graph.test.d.ts +2 -0
  54. package/dist/types/src/research/graph.test.d.ts.map +1 -0
  55. package/dist/types/src/research/index.d.ts +4 -0
  56. package/dist/types/src/research/index.d.ts.map +1 -0
  57. package/dist/types/src/research/research.d.ts +10 -0
  58. package/dist/types/src/research/research.d.ts.map +1 -0
  59. package/dist/types/src/research/research.test.d.ts.map +1 -0
  60. package/dist/types/src/session/index.d.ts +0 -1
  61. package/dist/types/src/session/index.d.ts.map +1 -1
  62. package/dist/types/src/session/session.d.ts +47 -22
  63. package/dist/types/src/session/session.d.ts.map +1 -1
  64. package/dist/types/src/session/version-pin.d.ts +3 -4
  65. package/dist/types/src/session/version-pin.d.ts.map +1 -1
  66. package/dist/types/src/summarization/summarization.test.d.ts +2 -0
  67. package/dist/types/src/summarization/summarization.test.d.ts.map +1 -0
  68. package/dist/types/src/testing/exa-search-1748337321991.d.ts +38 -0
  69. package/dist/types/src/testing/exa-search-1748337321991.d.ts.map +1 -0
  70. package/dist/types/src/testing/exa-search-1748337331526.d.ts +37 -0
  71. package/dist/types/src/testing/exa-search-1748337331526.d.ts.map +1 -0
  72. package/dist/types/src/testing/exa-search-1748337344119.d.ts +58 -0
  73. package/dist/types/src/testing/exa-search-1748337344119.d.ts.map +1 -0
  74. package/dist/types/src/testing/index.d.ts +2 -7
  75. package/dist/types/src/testing/index.d.ts.map +1 -1
  76. package/dist/types/src/types.d.ts +3 -0
  77. package/dist/types/src/types.d.ts.map +1 -0
  78. package/package.json +22 -38
  79. package/src/blueprint/blueprint.test.ts +142 -0
  80. package/src/blueprint/blueprint.ts +95 -0
  81. package/src/blueprint/index.ts +7 -0
  82. package/src/blueprint/logger.ts +66 -0
  83. package/src/blueprint/machine.ts +208 -0
  84. package/src/blueprint/test-data.ts +55 -0
  85. package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +95 -0
  86. package/src/extraction/extraction-llm-function/extraction-llm-function.ts +64 -0
  87. package/src/extraction/extraction-llm-function/index.ts +5 -0
  88. package/src/extraction/extraction-llm-function/instructions.tpl +28 -0
  89. package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +115 -0
  90. package/src/extraction/extraction-ner-function/extraction-ner-function.ts +54 -0
  91. package/src/extraction/extraction-ner-function/index.ts +6 -0
  92. package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +94 -0
  93. package/src/extraction/extraction-ner-function/named-entity-recognition.ts +97 -0
  94. package/src/extraction/extraction.ts +75 -0
  95. package/src/extraction/index.ts +8 -0
  96. package/src/extraction/quotes.test.ts +27 -0
  97. package/src/extraction/quotes.ts +57 -0
  98. package/src/index.ts +4 -4
  99. package/src/research/exa.ts +100 -0
  100. package/src/research/graph.test.ts +15 -0
  101. package/src/research/graph.ts +291 -0
  102. package/src/research/index.ts +7 -0
  103. package/src/research/instructions-research.tpl +97 -0
  104. package/src/research/research.test.ts +189 -0
  105. package/src/research/research.ts +89 -0
  106. package/src/session/index.ts +0 -1
  107. package/src/session/session.test.ts +7 -7
  108. package/src/session/session.ts +46 -19
  109. package/src/session/version-pin.ts +2 -3
  110. package/src/summarization/summarization.test.ts +216 -0
  111. package/src/testing/exa-search-1748337321991.ts +131 -0
  112. package/src/testing/exa-search-1748337331526.ts +144 -0
  113. package/src/testing/exa-search-1748337344119.ts +133 -0
  114. package/src/testing/index.ts +8 -8
  115. package/src/types.ts +8 -0
  116. package/src/typings.d.ts +8 -0
  117. package/dist/lib/browser/chunk-B4HAWUFW.mjs +0 -2786
  118. package/dist/lib/browser/chunk-B4HAWUFW.mjs.map +0 -7
  119. package/dist/lib/browser/testing/index.mjs +0 -658
  120. package/dist/lib/browser/testing/index.mjs.map +0 -7
  121. package/dist/lib/node/chunk-NOB7CIIC.cjs +0 -2791
  122. package/dist/lib/node/chunk-NOB7CIIC.cjs.map +0 -7
  123. package/dist/lib/node/testing/index.cjs +0 -672
  124. package/dist/lib/node/testing/index.cjs.map +0 -7
  125. package/dist/lib/node-esm/chunk-SAWYU3V5.mjs +0 -2788
  126. package/dist/lib/node-esm/chunk-SAWYU3V5.mjs.map +0 -7
  127. package/dist/lib/node-esm/testing/index.mjs +0 -659
  128. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  129. package/dist/types/src/ai-service/client.test.d.ts +0 -2
  130. package/dist/types/src/ai-service/client.test.d.ts.map +0 -1
  131. package/dist/types/src/ai-service/defs.d.ts +0 -9
  132. package/dist/types/src/ai-service/defs.d.ts.map +0 -1
  133. package/dist/types/src/ai-service/edge-client.d.ts +0 -18
  134. package/dist/types/src/ai-service/edge-client.d.ts.map +0 -1
  135. package/dist/types/src/ai-service/index.d.ts +0 -10
  136. package/dist/types/src/ai-service/index.d.ts.map +0 -1
  137. package/dist/types/src/ai-service/message-collector.d.ts +0 -82
  138. package/dist/types/src/ai-service/message-collector.d.ts.map +0 -1
  139. package/dist/types/src/ai-service/ollama-client.d.ts +0 -43
  140. package/dist/types/src/ai-service/ollama-client.d.ts.map +0 -1
  141. package/dist/types/src/ai-service/parser.d.ts.map +0 -1
  142. package/dist/types/src/ai-service/service.d.ts +0 -25
  143. package/dist/types/src/ai-service/service.d.ts.map +0 -1
  144. package/dist/types/src/ai-service/stream.d.ts +0 -40
  145. package/dist/types/src/ai-service/stream.d.ts.map +0 -1
  146. package/dist/types/src/ai-service/stream.test.d.ts +0 -2
  147. package/dist/types/src/ai-service/stream.test.d.ts.map +0 -1
  148. package/dist/types/src/ai-service/testing/index.d.ts +0 -3
  149. package/dist/types/src/ai-service/testing/index.d.ts.map +0 -1
  150. package/dist/types/src/ai-service/testing/mock.d.ts +0 -11
  151. package/dist/types/src/ai-service/testing/mock.d.ts.map +0 -1
  152. package/dist/types/src/ai-service/testing/test-stream.d.ts +0 -7
  153. package/dist/types/src/ai-service/testing/test-stream.d.ts.map +0 -1
  154. package/dist/types/src/ai-service/transform.d.ts +0 -27
  155. package/dist/types/src/ai-service/transform.d.ts.map +0 -1
  156. package/dist/types/src/ai-service/types.d.ts +0 -210
  157. package/dist/types/src/ai-service/types.d.ts.map +0 -1
  158. package/dist/types/src/ai-service/util/index.d.ts +0 -2
  159. package/dist/types/src/ai-service/util/index.d.ts.map +0 -1
  160. package/dist/types/src/ai-service/util/sse.d.ts +0 -39
  161. package/dist/types/src/ai-service/util/sse.d.ts.map +0 -1
  162. package/dist/types/src/experimental/conversation/conversation.d.ts +0 -61
  163. package/dist/types/src/experimental/conversation/conversation.d.ts.map +0 -1
  164. package/dist/types/src/experimental/conversation/conversation.test.d.ts +0 -2
  165. package/dist/types/src/experimental/conversation/conversation.test.d.ts.map +0 -1
  166. package/dist/types/src/experimental/conversation/index.d.ts +0 -2
  167. package/dist/types/src/experimental/conversation/index.d.ts.map +0 -1
  168. package/dist/types/src/experimental/conversation/types.d.ts +0 -78
  169. package/dist/types/src/experimental/conversation/types.d.ts.map +0 -1
  170. package/dist/types/src/experimental/cypher/ast.d.ts +0 -56
  171. package/dist/types/src/experimental/cypher/ast.d.ts.map +0 -1
  172. package/dist/types/src/experimental/cypher/combinators.d.ts +0 -14
  173. package/dist/types/src/experimental/cypher/combinators.d.ts.map +0 -1
  174. package/dist/types/src/experimental/cypher/combinators.test.d.ts +0 -2
  175. package/dist/types/src/experimental/cypher/combinators.test.d.ts.map +0 -1
  176. package/dist/types/src/experimental/cypher/echo-data-source.d.ts +0 -16
  177. package/dist/types/src/experimental/cypher/echo-data-source.d.ts.map +0 -1
  178. package/dist/types/src/experimental/cypher/execution-plan.d.ts +0 -49
  179. package/dist/types/src/experimental/cypher/execution-plan.d.ts.map +0 -1
  180. package/dist/types/src/experimental/cypher/execution-plan.test.d.ts +0 -2
  181. package/dist/types/src/experimental/cypher/execution-plan.test.d.ts.map +0 -1
  182. package/dist/types/src/experimental/cypher/index.d.ts +0 -5
  183. package/dist/types/src/experimental/cypher/index.d.ts.map +0 -1
  184. package/dist/types/src/experimental/cypher/parjs.d.ts +0 -4
  185. package/dist/types/src/experimental/cypher/parjs.d.ts.map +0 -1
  186. package/dist/types/src/experimental/cypher/parser.d.ts +0 -6
  187. package/dist/types/src/experimental/cypher/parser.d.ts.map +0 -1
  188. package/dist/types/src/experimental/cypher/query-executor.d.ts +0 -26
  189. package/dist/types/src/experimental/cypher/query-executor.d.ts.map +0 -1
  190. package/dist/types/src/experimental/cypher/query-executor.test.d.ts +0 -2
  191. package/dist/types/src/experimental/cypher/query-executor.test.d.ts.map +0 -1
  192. package/dist/types/src/experimental/cypher/schema.d.ts +0 -12
  193. package/dist/types/src/experimental/cypher/schema.d.ts.map +0 -1
  194. package/dist/types/src/experimental/cypher/schema.test.d.ts +0 -2
  195. package/dist/types/src/experimental/cypher/schema.test.d.ts.map +0 -1
  196. package/dist/types/src/experimental/index.d.ts +0 -3
  197. package/dist/types/src/experimental/index.d.ts.map +0 -1
  198. package/dist/types/src/experimental/ner/ner.test.d.ts +0 -2
  199. package/dist/types/src/experimental/ner/ner.test.d.ts.map +0 -1
  200. package/dist/types/src/experimental/research/exa.d.ts +0 -6
  201. package/dist/types/src/experimental/research/exa.d.ts.map +0 -1
  202. package/dist/types/src/experimental/research/research.test.d.ts.map +0 -1
  203. package/dist/types/src/session/tools.d.ts +0 -18
  204. package/dist/types/src/session/tools.d.ts.map +0 -1
  205. package/dist/types/src/testing/artifacts.test.d.ts +0 -1
  206. package/dist/types/src/testing/artifacts.test.d.ts.map +0 -1
  207. package/dist/types/src/testing/data.d.ts +0 -2
  208. package/dist/types/src/testing/data.d.ts.map +0 -1
  209. package/dist/types/src/testing/defs.d.ts +0 -5
  210. package/dist/types/src/testing/defs.d.ts.map +0 -1
  211. package/dist/types/src/testing/logger.d.ts +0 -12
  212. package/dist/types/src/testing/logger.d.ts.map +0 -1
  213. package/dist/types/src/testing/object-extraction.test.d.ts +0 -1
  214. package/dist/types/src/testing/object-extraction.test.d.ts.map +0 -1
  215. package/dist/types/src/testing/ollama.d.ts +0 -6
  216. package/dist/types/src/testing/ollama.d.ts.map +0 -1
  217. package/dist/types/src/testing/printer.d.ts +0 -6
  218. package/dist/types/src/testing/printer.d.ts.map +0 -1
  219. package/dist/types/src/testing/query-promts.d.ts +0 -5
  220. package/dist/types/src/testing/query-promts.d.ts.map +0 -1
  221. package/dist/types/src/testing/query.test.d.ts +0 -2
  222. package/dist/types/src/testing/query.test.d.ts.map +0 -1
  223. package/dist/types/src/testing/test-data.d.ts +0 -29
  224. package/dist/types/src/testing/test-data.d.ts.map +0 -1
  225. package/dist/types/src/testing/test-schema.d.ts +0 -52
  226. package/dist/types/src/testing/test-schema.d.ts.map +0 -1
  227. package/dist/types/src/util/index.d.ts +0 -2
  228. package/dist/types/src/util/index.d.ts.map +0 -1
  229. package/dist/types/src/util/trim.d.ts +0 -5
  230. package/dist/types/src/util/trim.d.ts.map +0 -1
  231. package/src/ai-service/client.test.ts +0 -247
  232. package/src/ai-service/defs.ts +0 -39
  233. package/src/ai-service/edge-client.ts +0 -60
  234. package/src/ai-service/index.ts +0 -13
  235. package/src/ai-service/message-collector.ts +0 -84
  236. package/src/ai-service/ollama-client.ts +0 -506
  237. package/src/ai-service/parser.ts +0 -369
  238. package/src/ai-service/service.ts +0 -31
  239. package/src/ai-service/stream.test.ts +0 -125
  240. package/src/ai-service/stream.ts +0 -118
  241. package/src/ai-service/testing/index.ts +0 -6
  242. package/src/ai-service/testing/mock.ts +0 -30
  243. package/src/ai-service/testing/test-stream.ts +0 -93
  244. package/src/ai-service/transform.ts +0 -121
  245. package/src/ai-service/types.ts +0 -112
  246. package/src/ai-service/util/index.ts +0 -5
  247. package/src/ai-service/util/sse.ts +0 -341
  248. package/src/bin/chat.ts +0 -79
  249. package/src/experimental/conversation/conversation.test.ts +0 -73
  250. package/src/experimental/conversation/conversation.ts +0 -142
  251. package/src/experimental/conversation/index.ts +0 -5
  252. package/src/experimental/conversation/types.ts +0 -126
  253. package/src/experimental/cypher/ast.ts +0 -75
  254. package/src/experimental/cypher/combinators.test.ts +0 -137
  255. package/src/experimental/cypher/combinators.ts +0 -148
  256. package/src/experimental/cypher/echo-data-source.ts +0 -105
  257. package/src/experimental/cypher/execution-plan.test.ts +0 -44
  258. package/src/experimental/cypher/execution-plan.ts +0 -208
  259. package/src/experimental/cypher/index.ts +0 -8
  260. package/src/experimental/cypher/parjs-shims.d.ts +0 -10
  261. package/src/experimental/cypher/parjs.ts +0 -10
  262. package/src/experimental/cypher/parser.ts +0 -19
  263. package/src/experimental/cypher/query-executor.test.ts +0 -47
  264. package/src/experimental/cypher/query-executor.ts +0 -145
  265. package/src/experimental/cypher/schema.test.ts +0 -17
  266. package/src/experimental/cypher/schema.ts +0 -86
  267. package/src/experimental/index.ts +0 -6
  268. package/src/experimental/ner/ner.test.ts +0 -163
  269. package/src/experimental/research/exa.ts +0 -38
  270. package/src/experimental/research/instructions.tpl +0 -64
  271. package/src/experimental/research/research.test.ts +0 -263
  272. package/src/session/tools.ts +0 -117
  273. package/src/testing/artifacts.test.ts +0 -182
  274. package/src/testing/data.ts +0 -13
  275. package/src/testing/defs.ts +0 -9
  276. package/src/testing/logger.ts +0 -129
  277. package/src/testing/object-extraction.test.ts +0 -71
  278. package/src/testing/ollama.ts +0 -15
  279. package/src/testing/printer.ts +0 -41
  280. package/src/testing/query-promts.ts +0 -75
  281. package/src/testing/query.test.ts +0 -88
  282. package/src/testing/test-data.ts +0 -379
  283. package/src/testing/test-schema.ts +0 -79
  284. package/src/util/index.ts +0 -5
  285. package/src/util/trim.ts +0 -15
  286. package/vendor/parjs-browser.mjs +0 -4
  287. package/vendor/parjs-default.mjs +0 -8
  288. /package/dist/types/{src/bin → bin}/chat.d.ts +0 -0
  289. /package/dist/types/src/{experimental/research → research}/research.test.d.ts +0 -0
@@ -1,369 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Message, type MessageContentBlock } from '@dxos/artifact';
6
- import { Event } from '@dxos/async';
7
- import { create } from '@dxos/echo-schema';
8
- import { invariant } from '@dxos/invariant';
9
- import { log } from '@dxos/log';
10
- import { isNotFalsy, safeParseJson } from '@dxos/util';
11
-
12
- import { type GenerationStream } from './service';
13
- import { StreamTransform, type StreamBlock } from './transform';
14
- import type { GenerationStreamEvent } from './types';
15
-
16
- /**
17
- * Parse mixed content of plain text, XML fragments, and JSON blocks.
18
- */
19
- export class MixedStreamParser {
20
- /**
21
- * New message.
22
- */
23
- public message = new Event<Message>();
24
-
25
- /**
26
- * Complete block added to Message.
27
- */
28
- public block = new Event<MessageContentBlock>();
29
-
30
- /**
31
- * Update partial block (while streaming).
32
- */
33
- public update = new Event<MessageContentBlock>();
34
-
35
- public streamEvent = new Event<GenerationStreamEvent>();
36
-
37
- /**
38
- * Current message.
39
- */
40
- private _message?: Message | undefined;
41
-
42
- private _emitBlock(contentBlock: MessageContentBlock, streamBlock?: StreamBlock) {
43
- const messageBlock = streamBlock ? mergeMessageBlock(contentBlock, streamBlock) : contentBlock;
44
- if (messageBlock) {
45
- if (messageBlock.type === 'text' && messageBlock.text.length === 0) {
46
- return;
47
- }
48
-
49
- invariant(this._message);
50
- this._message.content.push(messageBlock);
51
- this.block.emit(messageBlock);
52
- }
53
- }
54
-
55
- private _emitUpdate(contentBlock: MessageContentBlock, streamBlock: StreamBlock) {
56
- const messageBlock = mergeMessageBlock(contentBlock, streamBlock);
57
- if (messageBlock) {
58
- messageBlock.pending = true;
59
- this.update.emit(messageBlock);
60
- }
61
- }
62
-
63
- /**
64
- * Parse stream until end.
65
- */
66
- async parse(stream: GenerationStream): Promise<Message[]> {
67
- const transformer = new StreamTransform();
68
-
69
- /**
70
- * Current content message block.
71
- */
72
- let contentBlock: MessageContentBlock | undefined;
73
-
74
- /**
75
- * Current partial block used to accumulate content.
76
- */
77
- let streamBlock: StreamBlock | undefined;
78
- const stack: StreamBlock[] = [];
79
-
80
- const messagesCollected: Message[] = [];
81
-
82
- for await (const event of stream) {
83
- log('streamEvent', { event });
84
- this.streamEvent.emit(event);
85
-
86
- // log('event', { type: event.type, event });
87
- switch (event.type) {
88
- //
89
- // Messages.
90
- //
91
-
92
- case 'message_start': {
93
- if (this._message) {
94
- log.warn('unexpected message_start');
95
- }
96
-
97
- this._message = create(Message, { role: event.message.role, content: [...event.message.content] });
98
- this.message.emit(this._message);
99
- break;
100
- }
101
-
102
- case 'message_delta': {
103
- if (!this._message) {
104
- log.warn('unexpected message_delta');
105
- }
106
-
107
- break;
108
- }
109
-
110
- case 'message_stop': {
111
- if (!this._message) {
112
- log.warn('unexpected message_stop');
113
- } else {
114
- messagesCollected.push(this._message);
115
- this._message = undefined;
116
- }
117
- break;
118
- }
119
-
120
- //
121
- // Content blocks.
122
- //
123
-
124
- case 'content_block_start': {
125
- if (contentBlock) {
126
- log.warn('unexpected content_block_start', { content: contentBlock });
127
- }
128
-
129
- // TODO(burdon): Parse initial content (factor out from content_block_delta).
130
- contentBlock = event.content;
131
- break;
132
- }
133
-
134
- case 'content_block_delta': {
135
- if (!contentBlock) {
136
- log.warn('unexpected content_block_delta');
137
- break;
138
- }
139
-
140
- switch (event.delta.type) {
141
- //
142
- // Text
143
- //
144
- case 'text_delta': {
145
- const chunks = transformer.transform(event.delta.text);
146
- for (const chunk of chunks) {
147
- log('text_delta', { chunk });
148
-
149
- switch (streamBlock?.type) {
150
- //
151
- // XML Fragment.
152
- //
153
- case 'tag': {
154
- if (chunk.type === 'tag') {
155
- if (chunk.selfClosing) {
156
- streamBlock.content.push(chunk);
157
- } else if (chunk.closing) {
158
- if (stack.length > 0) {
159
- const top = stack.pop();
160
- invariant(top && top.type === 'tag');
161
- log('pop', { top });
162
- top.content.push(streamBlock);
163
- streamBlock = top;
164
- } else {
165
- this._emitBlock(contentBlock, streamBlock);
166
- streamBlock = undefined;
167
- }
168
- } else {
169
- stack.push(streamBlock);
170
- streamBlock = chunk;
171
- }
172
- } else {
173
- // Append text.
174
- if (streamBlock.content.length === 0) {
175
- streamBlock.content.push(chunk);
176
- } else {
177
- const last = streamBlock.content.at(-1);
178
- invariant(last);
179
- if (last.type === 'text') {
180
- last.content += chunk.content;
181
- } else {
182
- streamBlock.content.push(chunk);
183
- }
184
- }
185
- }
186
- break;
187
- }
188
-
189
- //
190
- // Text Fragment.
191
- //
192
- case 'text': {
193
- if (chunk.type === 'tag') {
194
- this._emitBlock(contentBlock, streamBlock);
195
- if (chunk.selfClosing) {
196
- this._emitBlock(contentBlock, chunk);
197
- streamBlock = undefined;
198
- } else {
199
- streamBlock = chunk;
200
- }
201
- } else {
202
- // Append text.
203
- streamBlock.content += chunk.content;
204
- }
205
- break;
206
- }
207
-
208
- //
209
- // No current chunk.
210
- //
211
- default: {
212
- if (chunk.type === 'tag' && chunk.selfClosing) {
213
- this._emitBlock(contentBlock, chunk);
214
- } else {
215
- streamBlock = chunk;
216
- }
217
- }
218
- }
219
- }
220
- break;
221
- }
222
-
223
- //
224
- // JSON
225
- //
226
- case 'input_json_delta': {
227
- if (!contentBlock) {
228
- log.warn('unexpected input_json_delta', { contentBlock });
229
- break;
230
- }
231
-
232
- if (streamBlock?.type === 'json') {
233
- streamBlock.content += event.delta.partial_json;
234
- } else {
235
- streamBlock = { type: 'json', content: event.delta.partial_json };
236
- }
237
- break;
238
- }
239
- }
240
- break;
241
- }
242
-
243
- case 'content_block_stop': {
244
- if (!contentBlock) {
245
- log.warn('unexpected content_block_stop');
246
- break;
247
- }
248
-
249
- this._emitBlock(contentBlock, streamBlock);
250
- contentBlock = undefined;
251
- streamBlock = undefined;
252
- break;
253
- }
254
- }
255
-
256
- if (contentBlock && streamBlock) {
257
- this._emitUpdate(contentBlock, streamBlock);
258
- }
259
- } // for.
260
-
261
- return messagesCollected;
262
- }
263
- }
264
-
265
- /**
266
- * Convert stream block to message content block.
267
- */
268
- export const mergeMessageBlock = (
269
- contentBlock: MessageContentBlock,
270
- streamBlock: StreamBlock,
271
- ): MessageContentBlock | undefined => {
272
- log('mergeMessageBlock', { contentBlock, streamBlock });
273
-
274
- switch (streamBlock.type) {
275
- //
276
- // Text
277
- //
278
- case 'text': {
279
- return { ...contentBlock, type: 'text', text: streamBlock.content };
280
- }
281
-
282
- //
283
- // XML
284
- //
285
- case 'tag': {
286
- switch (streamBlock.tag) {
287
- case 'cot': {
288
- const content = streamBlock.content
289
- .map((block) => {
290
- switch (block.type) {
291
- case 'text':
292
- return block.content;
293
- default:
294
- return null;
295
- }
296
- })
297
- .filter(isNotFalsy)
298
- .join('\n');
299
-
300
- return { ...contentBlock, type: 'text', disposition: 'cot', text: content };
301
- }
302
-
303
- case 'artifact': {
304
- const { attributes } = streamBlock;
305
- return { type: 'json', disposition: 'artifact', json: JSON.stringify(attributes) };
306
- }
307
-
308
- case 'suggest': {
309
- if (streamBlock.content.length === 1 && streamBlock.content[0].type === 'text') {
310
- return {
311
- type: 'json',
312
- disposition: 'suggest',
313
- json: JSON.stringify({ text: streamBlock.content[0].content }),
314
- };
315
- }
316
- break;
317
- }
318
-
319
- case 'proposal': {
320
- if (streamBlock.content.length === 1 && streamBlock.content[0].type === 'text') {
321
- return {
322
- type: 'json',
323
- disposition: 'proposal',
324
- json: JSON.stringify({ text: streamBlock.content[0].content }),
325
- };
326
- }
327
- break;
328
- }
329
-
330
- case 'select': {
331
- return {
332
- type: 'json',
333
- disposition: 'select',
334
- json: JSON.stringify({
335
- options: streamBlock.content.flatMap((content) =>
336
- content.type === 'tag' && content.content.length === 1 && content.content[0].type === 'text'
337
- ? [content.content[0].content]
338
- : [],
339
- ),
340
- }),
341
- };
342
- }
343
-
344
- case 'tool-list': {
345
- return {
346
- type: 'json',
347
- disposition: 'tool_list',
348
- json: JSON.stringify({}),
349
- };
350
- }
351
- }
352
-
353
- break;
354
- }
355
-
356
- //
357
- // JSON
358
- //
359
- case 'json': {
360
- switch (contentBlock.type) {
361
- case 'tool_use': {
362
- return { ...contentBlock, input: safeParseJson(streamBlock.content) ?? {} };
363
- }
364
- }
365
-
366
- return { ...contentBlock, type: 'json', disposition: 'artifact', json: streamBlock.content };
367
- }
368
- }
369
- };
@@ -1,31 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { type GenerateRequest, type GenerationStreamEvent, type GenerateResponse } from './types';
6
-
7
- /**
8
- * Interface for AI service.
9
- * Generates chat completions, supports, history and tools.
10
- */
11
- export interface AIServiceClient {
12
- /**
13
- * Generate chat completions, supports, history and tools.
14
- * Generate non-streaming response.
15
- */
16
- exec(request: GenerateRequest): Promise<GenerateResponse>;
17
-
18
- /**
19
- * Generate chat completions, supports, history and tools.
20
- * Process request and open message stream.
21
- */
22
- execStream(request: GenerateRequest): Promise<GenerationStream>;
23
- }
24
-
25
- /**
26
- * Streaming chat completion stream.
27
- */
28
- export interface GenerationStream extends AsyncIterable<GenerationStreamEvent> {
29
- abort(): void;
30
- complete(): Promise<void>;
31
- }
@@ -1,125 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { describe, test } from 'vitest';
6
-
7
- import { type Message } from '@dxos/artifact';
8
- import { log } from '@dxos/log';
9
-
10
- import { MixedStreamParser } from './parser';
11
- import { createGenerationStream } from './stream';
12
- import { createTestSSEStream } from './testing';
13
- import { type GenerationStreamEvent } from './types';
14
-
15
- // TODO(burdon): Tool request/response.
16
-
17
- const TEST_BLOCKS = [
18
- [
19
- // Text
20
- 'some text',
21
- 'on multiple lines.',
22
-
23
- // XML
24
- '<cot>',
25
- ' 1. Analyze content.',
26
- ' 2. Create plan.',
27
- ' 3. Generate artifacts.',
28
- '</cot>',
29
-
30
- // Text
31
- 'some more text.',
32
-
33
- // XML
34
- '<artifact id="123" />',
35
-
36
- // XML
37
- '<artifact id="456" />',
38
-
39
- // Text
40
- 'and some more text.',
41
-
42
- '<suggest>Plan me a trip to the Rio.</suggest>',
43
- '<suggest>Show me steak recipes.</suggest>',
44
- '<select><option>Yes</option><option>No</option></select>',
45
- ].join('\n'),
46
-
47
- // JSON
48
- {
49
- type: 'input',
50
- value: {
51
- level: 1,
52
- optional: true,
53
- },
54
- },
55
- ];
56
-
57
- describe('GenerationStream', () => {
58
- test('should generate a stream of blocks', async ({ expect }) => {
59
- const stream = createGenerationStream(new Response(createTestSSEStream(TEST_BLOCKS)));
60
- const events: GenerationStreamEvent[] = [];
61
- for await (const event of stream) {
62
- events.push(event);
63
- }
64
-
65
- expect(events.map((event) => event.type === 'content_block_start').filter(Boolean)).to.have.length(2);
66
- });
67
-
68
- for (const splitBy of ['word'] as const) {
69
- test(`should emit xml blocks (splitBy: ${splitBy})`, async ({ expect }) => {
70
- const stream = createGenerationStream(new Response(createTestSSEStream(TEST_BLOCKS, { splitBy })));
71
- const parser = new MixedStreamParser();
72
-
73
- let message: Message | undefined;
74
- parser.message.on((_message) => {
75
- message = _message;
76
- });
77
-
78
- await parser.parse(stream);
79
-
80
- for (const block of message?.content ?? []) {
81
- log('block', { block });
82
- }
83
- expect(message?.content.map((block) => block.type)).to.deep.eq([
84
- //
85
- 'text',
86
- 'text',
87
- 'text',
88
- 'json',
89
- 'text',
90
- 'json',
91
- 'text',
92
- 'json',
93
- 'text',
94
- 'json',
95
- 'text',
96
- 'json',
97
- 'json',
98
- ]);
99
- });
100
- }
101
-
102
- test.skip('invalid xml', async ({ expect }) => {
103
- const BLOCKS = [
104
- //
105
- '<cot> thoughts <tool-list> more thoughts </cot> <tool-list/>',
106
- ];
107
-
108
- const stream = createGenerationStream(new Response(createTestSSEStream(BLOCKS, { splitBy: 'word' })));
109
- const parser = new MixedStreamParser();
110
-
111
- const result = await parser.parse(stream);
112
- expect(result[0].content).to.deep.eq([
113
- {
114
- type: 'text',
115
- disposition: 'cot',
116
- text: 'thoughts more thoughts',
117
- },
118
- {
119
- type: 'json',
120
- disposition: 'tool_list',
121
- json: '{}',
122
- },
123
- ]);
124
- });
125
- });
@@ -1,118 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { Trigger } from '@dxos/async';
6
- import { log } from '@dxos/log';
7
-
8
- import type { GenerationStream } from './service';
9
- import { type GenerationStreamEvent } from './types';
10
- import { iterSSEMessages } from './util';
11
-
12
- /**
13
- * Creates a stream from an SSE response.
14
- */
15
- export const createGenerationStream = (response: Response, controller = new AbortController()): GenerationStream => {
16
- const iterator = async function* () {
17
- for await (const sse of iterSSEMessages(response, controller)) {
18
- if (sse.event === 'completion') {
19
- try {
20
- yield JSON.parse(sse.data);
21
- } catch (err) {
22
- log.error('could not parse message into JSON:', { data: sse.data, raw: sse.raw });
23
- throw err;
24
- }
25
- }
26
-
27
- if (
28
- sse.event === 'message_start' ||
29
- sse.event === 'message_delta' ||
30
- sse.event === 'message_stop' ||
31
- sse.event === 'content_block_start' ||
32
- sse.event === 'content_block_delta' ||
33
- sse.event === 'content_block_stop'
34
- ) {
35
- try {
36
- yield JSON.parse(sse.data);
37
- } catch (err) {
38
- log.error('could not parse message into JSON:', { data: sse.data, raw: sse.raw });
39
- throw err;
40
- }
41
- }
42
-
43
- if (sse.event === 'ping') {
44
- continue;
45
- }
46
-
47
- if (sse.event === 'error') {
48
- throw new Error(`Message generation error: ${sse.data}`);
49
- }
50
- }
51
- };
52
-
53
- return new GenerationStreamImpl(controller, iterator);
54
- };
55
-
56
- /**
57
- * Server-Sent Events (SSE) stream from the AI service.
58
- * https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events
59
- */
60
- export class GenerationStreamImpl implements GenerationStream {
61
- /**
62
- * Trigger event when the stream is done.
63
- */
64
- private readonly _done = new Trigger();
65
-
66
- /**
67
- * Iterator over the stream.
68
- */
69
- private _iterator?: AsyncIterator<GenerationStreamEvent> = undefined;
70
-
71
- constructor(
72
- private readonly _controller: AbortController,
73
- private readonly _getIterator: () => AsyncIterableIterator<GenerationStreamEvent>,
74
- ) {}
75
-
76
- /**
77
- * Returns an iterator over the stream.
78
- */
79
- [Symbol.asyncIterator](): AsyncIterator<GenerationStreamEvent> {
80
- return this._createIterator();
81
- }
82
-
83
- /**
84
- * Aborts the stream.
85
- */
86
- abort() {
87
- this._controller.abort();
88
- }
89
-
90
- /**
91
- * Returns the complete message list generated by the AI service.
92
- */
93
- async complete() {
94
- await this._done.wait();
95
- }
96
-
97
- /**
98
- * Creates an iterator over the stream.
99
- */
100
- private _createIterator(): AsyncIterator<GenerationStreamEvent> {
101
- const self = this;
102
- return (this._iterator ??= (() => {
103
- const generator = async function* (this: GenerationStreamImpl) {
104
- try {
105
- for await (const event of self._getIterator()) {
106
- yield event;
107
- }
108
- this._done.wake();
109
- } catch (err: any) {
110
- this._done.throw(err);
111
- throw err;
112
- }
113
- };
114
-
115
- return generator.call(this);
116
- })());
117
- }
118
- }
@@ -1,6 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- export * from './mock';
6
- export * from './test-stream';
@@ -1,30 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import {
6
- type GenerationStream,
7
- type AIServiceClient,
8
- type GenerateRequest,
9
- createGenerationStream,
10
- type GenerateResponse,
11
- } from '@dxos/assistant';
12
-
13
- import { createTestSSEStream } from './test-stream';
14
-
15
- export class MockAIService implements AIServiceClient {
16
- constructor(private readonly _responses: string[]) {}
17
-
18
- /**
19
- * Generate non-streaming response.
20
- */
21
- async exec(request: GenerateRequest): Promise<GenerateResponse> {
22
- throw new Error('Not implemented');
23
- }
24
-
25
- // TODO(burdon): Match response to request.
26
- // TODO(burdon): See MockGpt (from conductor).
27
- async execStream(request: GenerateRequest): Promise<GenerationStream> {
28
- return createGenerationStream(new Response(createTestSSEStream(this._responses)));
29
- }
30
- }