@dxos/assistant 0.8.1 → 0.8.2-main.10c050d

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 (277) hide show
  1. package/dist/lib/browser/index.mjs +1830 -228
  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 +1825 -229
  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 +1831 -228
  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/blueprint/machine.d.ts +113 -0
  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 -3
  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 +2 -0
  60. package/dist/types/src/research/research.test.d.ts.map +1 -0
  61. package/dist/types/src/session/index.d.ts +1 -0
  62. package/dist/types/src/session/index.d.ts.map +1 -1
  63. package/dist/types/src/session/session.d.ts +80 -35
  64. package/dist/types/src/session/session.d.ts.map +1 -1
  65. package/dist/types/src/session/version-pin.d.ts +21 -0
  66. package/dist/types/src/session/version-pin.d.ts.map +1 -0
  67. package/dist/types/src/session/version-pin.test.d.ts +2 -0
  68. package/dist/types/src/session/version-pin.test.d.ts.map +1 -0
  69. package/dist/types/src/summarization/summarization.test.d.ts +2 -0
  70. package/dist/types/src/summarization/summarization.test.d.ts.map +1 -0
  71. package/dist/types/src/testing/exa-search-1748337321991.d.ts +38 -0
  72. package/dist/types/src/testing/exa-search-1748337321991.d.ts.map +1 -0
  73. package/dist/types/src/testing/exa-search-1748337331526.d.ts +37 -0
  74. package/dist/types/src/testing/exa-search-1748337331526.d.ts.map +1 -0
  75. package/dist/types/src/testing/exa-search-1748337344119.d.ts +58 -0
  76. package/dist/types/src/testing/exa-search-1748337344119.d.ts.map +1 -0
  77. package/dist/types/src/testing/index.d.ts +2 -6
  78. package/dist/types/src/testing/index.d.ts.map +1 -1
  79. package/dist/types/src/types.d.ts +3 -0
  80. package/dist/types/src/types.d.ts.map +1 -0
  81. package/dist/types/tsconfig.tsbuildinfo +1 -1
  82. package/package.json +25 -35
  83. package/src/blueprint/blueprint.test.ts +142 -0
  84. package/src/blueprint/blueprint.ts +95 -0
  85. package/src/blueprint/index.ts +7 -0
  86. package/src/blueprint/logger.ts +66 -0
  87. package/src/blueprint/machine.ts +208 -0
  88. package/src/blueprint/test-data.ts +55 -0
  89. package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +95 -0
  90. package/src/extraction/extraction-llm-function/extraction-llm-function.ts +64 -0
  91. package/src/extraction/extraction-llm-function/index.ts +5 -0
  92. package/src/extraction/extraction-llm-function/instructions.tpl +28 -0
  93. package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +115 -0
  94. package/src/extraction/extraction-ner-function/extraction-ner-function.ts +54 -0
  95. package/src/extraction/extraction-ner-function/index.ts +6 -0
  96. package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +94 -0
  97. package/src/extraction/extraction-ner-function/named-entity-recognition.ts +97 -0
  98. package/src/extraction/extraction.ts +75 -0
  99. package/src/extraction/index.ts +8 -0
  100. package/src/extraction/quotes.test.ts +27 -0
  101. package/src/extraction/quotes.ts +57 -0
  102. package/src/index.ts +4 -3
  103. package/src/research/exa.ts +100 -0
  104. package/src/research/graph.test.ts +15 -0
  105. package/src/research/graph.ts +291 -0
  106. package/src/research/index.ts +7 -0
  107. package/src/research/instructions-research.tpl +97 -0
  108. package/src/research/research.test.ts +189 -0
  109. package/src/research/research.ts +89 -0
  110. package/src/session/index.ts +1 -0
  111. package/src/session/session.test.ts +39 -67
  112. package/src/session/session.ts +328 -155
  113. package/src/session/version-pin.test.ts +26 -0
  114. package/src/session/version-pin.ts +48 -0
  115. package/src/summarization/summarization.test.ts +216 -0
  116. package/src/testing/exa-search-1748337321991.ts +131 -0
  117. package/src/testing/exa-search-1748337331526.ts +144 -0
  118. package/src/testing/exa-search-1748337344119.ts +133 -0
  119. package/src/testing/index.ts +8 -7
  120. package/src/typedefs.d.ts +8 -0
  121. package/src/types.ts +8 -0
  122. package/src/typings.d.ts +8 -0
  123. package/dist/lib/browser/chunk-PND5VR6D.mjs +0 -2315
  124. package/dist/lib/browser/chunk-PND5VR6D.mjs.map +0 -7
  125. package/dist/lib/browser/testing/index.mjs +0 -621
  126. package/dist/lib/browser/testing/index.mjs.map +0 -7
  127. package/dist/lib/node/chunk-IBOBRBDF.cjs +0 -2326
  128. package/dist/lib/node/chunk-IBOBRBDF.cjs.map +0 -7
  129. package/dist/lib/node/testing/index.cjs +0 -637
  130. package/dist/lib/node/testing/index.cjs.map +0 -7
  131. package/dist/lib/node-esm/chunk-DCQJOLSR.mjs +0 -2317
  132. package/dist/lib/node-esm/chunk-DCQJOLSR.mjs.map +0 -7
  133. package/dist/lib/node-esm/testing/index.mjs +0 -622
  134. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  135. package/dist/types/src/ai-service/client.test.d.ts +0 -2
  136. package/dist/types/src/ai-service/client.test.d.ts.map +0 -1
  137. package/dist/types/src/ai-service/defs.d.ts +0 -9
  138. package/dist/types/src/ai-service/defs.d.ts.map +0 -1
  139. package/dist/types/src/ai-service/edge-client.d.ts +0 -19
  140. package/dist/types/src/ai-service/edge-client.d.ts.map +0 -1
  141. package/dist/types/src/ai-service/index.d.ts +0 -10
  142. package/dist/types/src/ai-service/index.d.ts.map +0 -1
  143. package/dist/types/src/ai-service/message-collector.d.ts +0 -88
  144. package/dist/types/src/ai-service/message-collector.d.ts.map +0 -1
  145. package/dist/types/src/ai-service/ollama-client.d.ts +0 -39
  146. package/dist/types/src/ai-service/ollama-client.d.ts.map +0 -1
  147. package/dist/types/src/ai-service/parser.d.ts +0 -138
  148. package/dist/types/src/ai-service/parser.d.ts.map +0 -1
  149. package/dist/types/src/ai-service/service.d.ts +0 -9
  150. package/dist/types/src/ai-service/service.d.ts.map +0 -1
  151. package/dist/types/src/ai-service/stream.d.ts +0 -40
  152. package/dist/types/src/ai-service/stream.d.ts.map +0 -1
  153. package/dist/types/src/ai-service/stream.test.d.ts +0 -2
  154. package/dist/types/src/ai-service/stream.test.d.ts.map +0 -1
  155. package/dist/types/src/ai-service/testing/index.d.ts +0 -3
  156. package/dist/types/src/ai-service/testing/index.d.ts.map +0 -1
  157. package/dist/types/src/ai-service/testing/mock.d.ts +0 -7
  158. package/dist/types/src/ai-service/testing/mock.d.ts.map +0 -1
  159. package/dist/types/src/ai-service/testing/test-stream.d.ts +0 -7
  160. package/dist/types/src/ai-service/testing/test-stream.d.ts.map +0 -1
  161. package/dist/types/src/ai-service/transform.d.ts +0 -27
  162. package/dist/types/src/ai-service/transform.d.ts.map +0 -1
  163. package/dist/types/src/ai-service/types.d.ts +0 -167
  164. package/dist/types/src/ai-service/types.d.ts.map +0 -1
  165. package/dist/types/src/ai-service/util/index.d.ts +0 -2
  166. package/dist/types/src/ai-service/util/index.d.ts.map +0 -1
  167. package/dist/types/src/ai-service/util/sse.d.ts +0 -39
  168. package/dist/types/src/ai-service/util/sse.d.ts.map +0 -1
  169. package/dist/types/src/conversation/conversation.d.ts +0 -80
  170. package/dist/types/src/conversation/conversation.d.ts.map +0 -1
  171. package/dist/types/src/conversation/conversation.test.d.ts +0 -2
  172. package/dist/types/src/conversation/conversation.test.d.ts.map +0 -1
  173. package/dist/types/src/conversation/index.d.ts +0 -2
  174. package/dist/types/src/conversation/index.d.ts.map +0 -1
  175. package/dist/types/src/conversation/types.d.ts +0 -79
  176. package/dist/types/src/conversation/types.d.ts.map +0 -1
  177. package/dist/types/src/cypher/ast.d.ts +0 -56
  178. package/dist/types/src/cypher/ast.d.ts.map +0 -1
  179. package/dist/types/src/cypher/combinators.d.ts +0 -14
  180. package/dist/types/src/cypher/combinators.d.ts.map +0 -1
  181. package/dist/types/src/cypher/combinators.test.d.ts +0 -2
  182. package/dist/types/src/cypher/combinators.test.d.ts.map +0 -1
  183. package/dist/types/src/cypher/echo-data-source.d.ts +0 -16
  184. package/dist/types/src/cypher/echo-data-source.d.ts.map +0 -1
  185. package/dist/types/src/cypher/execution-plan.d.ts +0 -49
  186. package/dist/types/src/cypher/execution-plan.d.ts.map +0 -1
  187. package/dist/types/src/cypher/execution-plan.test.d.ts +0 -2
  188. package/dist/types/src/cypher/execution-plan.test.d.ts.map +0 -1
  189. package/dist/types/src/cypher/index.d.ts +0 -5
  190. package/dist/types/src/cypher/index.d.ts.map +0 -1
  191. package/dist/types/src/cypher/parjs.d.ts +0 -4
  192. package/dist/types/src/cypher/parjs.d.ts.map +0 -1
  193. package/dist/types/src/cypher/parser.d.ts +0 -6
  194. package/dist/types/src/cypher/parser.d.ts.map +0 -1
  195. package/dist/types/src/cypher/query-executor.d.ts +0 -26
  196. package/dist/types/src/cypher/query-executor.d.ts.map +0 -1
  197. package/dist/types/src/cypher/query-executor.test.d.ts +0 -2
  198. package/dist/types/src/cypher/query-executor.test.d.ts.map +0 -1
  199. package/dist/types/src/cypher/schema.d.ts +0 -12
  200. package/dist/types/src/cypher/schema.d.ts.map +0 -1
  201. package/dist/types/src/cypher/schema.test.d.ts +0 -2
  202. package/dist/types/src/cypher/schema.test.d.ts.map +0 -1
  203. package/dist/types/src/testing/artifacts.test.d.ts +0 -1
  204. package/dist/types/src/testing/artifacts.test.d.ts.map +0 -1
  205. package/dist/types/src/testing/data.d.ts +0 -2
  206. package/dist/types/src/testing/data.d.ts.map +0 -1
  207. package/dist/types/src/testing/defs.d.ts +0 -5
  208. package/dist/types/src/testing/defs.d.ts.map +0 -1
  209. package/dist/types/src/testing/logger.d.ts +0 -12
  210. package/dist/types/src/testing/logger.d.ts.map +0 -1
  211. package/dist/types/src/testing/object-extraction.test.d.ts +0 -1
  212. package/dist/types/src/testing/object-extraction.test.d.ts.map +0 -1
  213. package/dist/types/src/testing/ollama.d.ts +0 -6
  214. package/dist/types/src/testing/ollama.d.ts.map +0 -1
  215. package/dist/types/src/testing/query-promts.d.ts +0 -5
  216. package/dist/types/src/testing/query-promts.d.ts.map +0 -1
  217. package/dist/types/src/testing/query.test.d.ts +0 -2
  218. package/dist/types/src/testing/query.test.d.ts.map +0 -1
  219. package/dist/types/src/testing/test-data.d.ts +0 -29
  220. package/dist/types/src/testing/test-data.d.ts.map +0 -1
  221. package/dist/types/src/testing/test-schema.d.ts +0 -50
  222. package/dist/types/src/testing/test-schema.d.ts.map +0 -1
  223. package/dist/types/src/util/index.d.ts +0 -2
  224. package/dist/types/src/util/index.d.ts.map +0 -1
  225. package/dist/types/src/util/trim.d.ts +0 -5
  226. package/dist/types/src/util/trim.d.ts.map +0 -1
  227. package/src/ai-service/client.test.ts +0 -265
  228. package/src/ai-service/defs.ts +0 -39
  229. package/src/ai-service/edge-client.ts +0 -67
  230. package/src/ai-service/index.ts +0 -13
  231. package/src/ai-service/message-collector.ts +0 -84
  232. package/src/ai-service/ollama-client.ts +0 -499
  233. package/src/ai-service/parser.ts +0 -358
  234. package/src/ai-service/service.ts +0 -15
  235. package/src/ai-service/stream.test.ts +0 -125
  236. package/src/ai-service/stream.ts +0 -118
  237. package/src/ai-service/testing/index.ts +0 -6
  238. package/src/ai-service/testing/mock.ts +0 -22
  239. package/src/ai-service/testing/test-stream.ts +0 -93
  240. package/src/ai-service/transform.ts +0 -121
  241. package/src/ai-service/types.ts +0 -103
  242. package/src/ai-service/util/index.ts +0 -5
  243. package/src/ai-service/util/sse.ts +0 -341
  244. package/src/bin/chat.ts +0 -79
  245. package/src/conversation/conversation.test.ts +0 -73
  246. package/src/conversation/conversation.ts +0 -257
  247. package/src/conversation/index.ts +0 -5
  248. package/src/conversation/types.ts +0 -129
  249. package/src/cypher/ast.ts +0 -75
  250. package/src/cypher/combinators.test.ts +0 -137
  251. package/src/cypher/combinators.ts +0 -148
  252. package/src/cypher/echo-data-source.ts +0 -105
  253. package/src/cypher/execution-plan.test.ts +0 -44
  254. package/src/cypher/execution-plan.ts +0 -208
  255. package/src/cypher/index.ts +0 -8
  256. package/src/cypher/parjs-shims.d.ts +0 -10
  257. package/src/cypher/parjs.ts +0 -10
  258. package/src/cypher/parser.ts +0 -19
  259. package/src/cypher/query-executor.test.ts +0 -47
  260. package/src/cypher/query-executor.ts +0 -145
  261. package/src/cypher/schema.test.ts +0 -17
  262. package/src/cypher/schema.ts +0 -86
  263. package/src/testing/artifacts.test.ts +0 -182
  264. package/src/testing/data.ts +0 -13
  265. package/src/testing/defs.ts +0 -9
  266. package/src/testing/logger.ts +0 -129
  267. package/src/testing/object-extraction.test.ts +0 -71
  268. package/src/testing/ollama.ts +0 -15
  269. package/src/testing/query-promts.ts +0 -75
  270. package/src/testing/query.test.ts +0 -91
  271. package/src/testing/test-data.ts +0 -372
  272. package/src/testing/test-schema.ts +0 -80
  273. package/src/util/index.ts +0 -5
  274. package/src/util/trim.ts +0 -15
  275. package/vendor/parjs-browser.mjs +0 -4
  276. package/vendor/parjs-default.mjs +0 -8
  277. /package/dist/types/{src/bin → bin}/chat.d.ts +0 -0
@@ -1,137 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- /* eslint-disable unused-imports/no-unused-vars */
6
- /* eslint-disable @typescript-eslint/consistent-type-imports */
7
-
8
- import { createRequire } from 'node:module';
9
- import { type Parjser } from 'parjs';
10
- import { describe, test } from 'vitest';
11
-
12
- import { log } from '@dxos/log';
13
-
14
- import {
15
- cypherQuery,
16
- identifier,
17
- matchClause,
18
- nodePattern,
19
- properties,
20
- returnClause,
21
- whereClause,
22
- } from './combinators';
23
-
24
- describe('Cypher Combinators', () => {
25
- // TODO(dmaretskyi): Must be like this or it breaks vitest.
26
- const require = createRequire(import.meta.url);
27
- const { string, regexp, whitespace } = require('parjs') as typeof import('parjs');
28
- const { between, many, manySepBy, or, map, then, recover } =
29
- require('parjs/combinators') as typeof import('parjs/combinators');
30
-
31
- test('string', ({ expect }) => {
32
- expect(string('hello').parse('hello')).toMatchObject({ isOk: true });
33
- });
34
-
35
- test('string with whitespace', ({ expect }) => {
36
- const ws = whitespace(); // Parses whitespace
37
- // many;
38
- // const optionalWs = many(100)(ws);
39
-
40
- expect(string('hello').parse('hello')).toMatchObject({ isOk: true });
41
- });
42
-
43
- test('optional vairable tag', ({ expect }) => {
44
- const node = identifier.pipe(
45
- then(':'),
46
- recover(() => ({ kind: 'Soft' })),
47
- or(''),
48
- then(identifier),
49
- between('(', ')'),
50
- );
51
- const relation = identifier.pipe(
52
- then(':'),
53
- recover(() => ({ kind: 'Soft' })),
54
- or(''),
55
- then(identifier),
56
- between('[', ']'),
57
- );
58
- const parser = or(node)(relation);
59
- const input = '[a:b]';
60
- const result = parser.parse(input);
61
- log('result', { result });
62
- });
63
-
64
- test('properties', ({ expect }) => {
65
- const input = "{name: 'John'}";
66
- const result = properties.parse(input);
67
- log('result', { result });
68
- expect(result).toMatchObject({ isOk: true });
69
- });
70
-
71
- test('node pattern', ({ expect }) => {
72
- testParser(nodePattern, '(:Person)');
73
- testParser(nodePattern, '(n:Person)');
74
- testParser(nodePattern, "(n:Person {name: 'John'})");
75
- });
76
-
77
- test('match clause', ({ expect }) => {
78
- testParser(matchClause, 'MATCH (n:Person)');
79
- testParser(matchClause, 'MATCH (n:Person)-[r:KNOWS]->(m:Person)');
80
- testParser(matchClause, 'MATCH (o:Org)-[:HAS_EMPLOYEE]->(e:Employee)');
81
- });
82
-
83
- test('where clause', ({ expect }) => {
84
- testParser(whereClause, 'WHERE n.name = "John"');
85
- testParser(whereClause, 'WHERE o.name = "DXOS" AND p.name = "Composer"');
86
- });
87
-
88
- test('return clause', ({ expect }) => {
89
- testParser(returnClause, 'RETURN n, m');
90
- testParser(returnClause, 'RETURN m.name AS employee');
91
-
92
- const cases = ['RETURN n, m'];
93
- for (const input of cases) {
94
- const result = returnClause.parse(input);
95
- log('result', { result });
96
- expect(result).toMatchObject({ isOk: true });
97
- }
98
- });
99
-
100
- test('query', async ({ expect }) => {
101
- testParser(cypherQuery, 'MATCH (n:Person) RETURN n');
102
- testParser(
103
- cypherQuery,
104
- `
105
- MATCH (n:Person {name: 'John'})-[r:KNOWS]->(m:Person)
106
- RETURN n, m
107
- `,
108
- );
109
- testParser(
110
- cypherQuery,
111
- `
112
- MATCH (n:Person)-[r:KNOWS]->(m:Person)
113
- WHERE n.name = "John"
114
- RETURN n, m
115
- `,
116
- );
117
- testParser(
118
- cypherQuery,
119
- 'MATCH (o:Org)-[:HAS_EMPLOYEE]->(e:Employee)-[:WORKS_ON]->(p:Project) WHERE o.name = "DXOS" AND p.name = "Composer" RETURN e.name, e.id, p.name, p.id',
120
- );
121
- testParser(
122
- cypherQuery,
123
- 'MATCH (n:Org {name: "DXOS"})-[:HAS_EMPLOYEE]->(m:Employee)<-[:WORKS_ON]-(p:Project {name: "Composer"}) RETURN m.name AS employee',
124
- );
125
- testParser(
126
- cypherQuery,
127
- "MATCH (org:Org {name: 'DXOS'})-[:ORG_EMPLOYEES]->(c:Contact)<-[:TASK_ASSIGNEE]-(t:Task)-[:TASK_PROJECT]->(p:Project {name: 'Composer'}) RETURN c.name",
128
- );
129
- });
130
- });
131
-
132
- const testParser = (parser: Parjser<any>, input: string) => {
133
- const result = parser.parse(input);
134
- if (!result.isOk) {
135
- throw new Error(`Failed to parse: ${result}`);
136
- }
137
- };
@@ -1,148 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- /* eslint-disable unused-imports/no-unused-vars */
6
- /* eslint-disable @typescript-eslint/consistent-type-imports */
7
-
8
- import type {
9
- CypherQuery,
10
- EqualsPredicate,
11
- GraphPattern,
12
- GraphPatternConnector,
13
- Identifier,
14
- MatchClause,
15
- MemberExpression,
16
- NodePattern,
17
- Properties,
18
- Property,
19
- RelationshipPattern,
20
- ReturnClause,
21
- StringLiteral,
22
- WhereClause,
23
- } from './ast';
24
- import { Parjser, parjs, parjsCombinators } from './parjs';
25
-
26
- // Helper parsers
27
- const ws = parjs.whitespace(); // Parses whitespace
28
-
29
- const nothing = parjs.string('').pipe(parjsCombinators.map(() => null)); // Parses nothing
30
-
31
- const optional = <T>(parser: Parjser<T>) =>
32
- parser.pipe(
33
- parjsCombinators.recover(() => ({ kind: 'Soft' })),
34
- parjsCombinators.or(nothing),
35
- ); // Makes a parser optional
36
-
37
- const keyword = (word: string) => parjs.string(word).pipe(parjsCombinators.map(() => word)); // Parses specific keywords
38
-
39
- // Identifiers (node labels, relationship types, variables, etc.)
40
- export const identifier = parjs.regexp(/[a-zA-Z_][a-zA-Z0-9_]*/).pipe(
41
- parjsCombinators.map((match): Identifier => ({ astKind: 'Identifier', name: match[0] })), // Extract the matched string
42
- );
43
-
44
- // Literals (numbers and strings)
45
- const numberLiteral = parjs.regexp(/-?\d+(\.\d+)?/).pipe(parjsCombinators.map(Number)); // Numbers
46
- const stringLiteral = parjs.regexp(/"([^"]*)"|'([^']*)'/).pipe(
47
- parjsCombinators.map((match): StringLiteral => ({ astKind: 'StringLiteral', value: match[1] || match[2] })), // Extract content without quotes
48
- );
49
-
50
- // Node pattern (e.g., "(n:Person {name: 'John'})"
51
- const variableTag = identifier.pipe(parjsCombinators.map((variable) => variable)).expects('variable tag');
52
- export const label = identifier.pipe(parjsCombinators.map((name) => name));
53
- export const property = identifier.pipe(
54
- parjsCombinators.then(parjs.string(':'), ws, stringLiteral),
55
- parjsCombinators.map(([key, , , value]): Property => ({ key, value })),
56
- );
57
- export const properties = property.pipe(
58
- parjsCombinators.manySepBy(','),
59
- parjsCombinators.between('{', '}'),
60
- parjsCombinators.map((properties): Properties => ({ astKind: 'Properties', properties })),
61
- );
62
- export const nodePattern = optional(variableTag).pipe(
63
- parjsCombinators.then(':'),
64
- parjsCombinators.then(ws, label, ws),
65
- parjsCombinators.then(optional(properties)),
66
- parjsCombinators.between('(', ')'),
67
- parjsCombinators.map(
68
- ([[[variable], _, label], properties]): NodePattern => ({ astKind: 'NodePattern', variable, label, properties }),
69
- ),
70
- );
71
-
72
- export const relationshipPattern = optional(variableTag).pipe(
73
- parjsCombinators.then(':'),
74
- parjsCombinators.then(ws, label, ws),
75
- parjsCombinators.then(optional(properties)),
76
- parjsCombinators.between('[', ']'),
77
- parjsCombinators.map(
78
- ([[[variable], _, label], properties]): RelationshipPattern => ({
79
- astKind: 'RelationshipPattern',
80
- variable,
81
- label,
82
- properties,
83
- }),
84
- ),
85
- );
86
-
87
- const graphPatternConnector = parjs.string('->').pipe(
88
- parjsCombinators.or('<-' as const, '-' as const),
89
- parjsCombinators.map((x): GraphPatternConnector => ({ astKind: 'GraphPatternConnector', direction: x })),
90
- );
91
-
92
- export const graphPattern = nodePattern.pipe(
93
- parjsCombinators.or(relationshipPattern),
94
- parjsCombinators.manySepBy(graphPatternConnector),
95
- parjsCombinators.map((segments): GraphPattern => ({ astKind: 'GraphPattern', segments })),
96
- );
97
-
98
- export const matchClause = keyword('MATCH').pipe(
99
- parjsCombinators.then(ws),
100
- parjsCombinators.then(graphPattern),
101
- parjsCombinators.map(([, pattern]): MatchClause => ({ astKind: 'MatchClause', pattern })),
102
- );
103
-
104
- const memberExpression = identifier.pipe(
105
- parjsCombinators.manySepBy('.'),
106
- parjsCombinators.map((path): MemberExpression => ({ astKind: 'MemberExpression', path })),
107
- );
108
-
109
- const equalsPredicate = memberExpression.pipe(
110
- parjsCombinators.then(ws, parjs.string('='), ws, stringLiteral),
111
- parjsCombinators.map(([left, , , , right]): EqualsPredicate => ({ astKind: 'EqualsPredicate', left, right })),
112
- );
113
-
114
- export const whereClause = keyword('WHERE').pipe(
115
- parjsCombinators.then(
116
- ws,
117
- equalsPredicate.pipe(parjsCombinators.between(ws, ws), parjsCombinators.manySepBy(parjs.string('AND'))),
118
- ws,
119
- ),
120
- parjsCombinators.map(([, , predicates]): WhereClause => ({ astKind: 'WhereClause', predicates })),
121
- );
122
-
123
- export const returnClause = keyword('RETURN').pipe(
124
- parjsCombinators.then(
125
- ws,
126
- memberExpression.pipe(
127
- parjsCombinators.then(
128
- optional(parjs.string('AS').pipe(parjsCombinators.between(ws), parjsCombinators.then(identifier))),
129
- ws,
130
- ),
131
- parjsCombinators.manySepBy(parjs.string(',').pipe(parjsCombinators.then(ws))),
132
- ),
133
- ws,
134
- ),
135
- parjsCombinators.map(([, , fields]): ReturnClause => ({ astKind: 'ReturnClause', fields: fields.map(([f]) => f) })),
136
- );
137
-
138
- export const cypherQuery = ws.pipe(
139
- parjsCombinators.then(matchClause, ws, optional(whereClause), ws, returnClause, ws),
140
- parjsCombinators.map(
141
- ([, matchClause, , whereClause, , returnClause]): CypherQuery => ({
142
- astKind: 'CypherQuery',
143
- matchClause,
144
- whereClause,
145
- returnClause,
146
- }),
147
- ),
148
- );
@@ -1,105 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { raise } from '@dxos/debug';
6
- import { type EchoDatabase, Filter, type ReactiveEchoObject } from '@dxos/echo-db';
7
- import { type S, getSchemaTypename, StoredSchema, toJsonSchema } from '@dxos/echo-schema';
8
- import { getSchema } from '@dxos/live-object';
9
- import { log } from '@dxos/log';
10
-
11
- import type { DataSource, Node, Relationship } from './query-executor';
12
- import { formatInferredRelationshipLabel, formatNodeLabel, isReference } from './schema';
13
-
14
- export class EchoDataSource implements DataSource {
15
- constructor(private readonly _db: EchoDatabase) {}
16
-
17
- @log.method()
18
- async getNodes({ label }: { label?: string }): Promise<Node[]> {
19
- if (!label) {
20
- const { objects } = await this._db.query().run();
21
- return objects.map(this._objectToNode);
22
- }
23
-
24
- const schema = (await this._getAllSchema()).find((s) => getSchemaTypename(s)?.endsWith(label));
25
-
26
- if (!schema) {
27
- return [];
28
- }
29
-
30
- const { objects } = await this._db.query(Filter.schema(schema)).run();
31
- return objects.map(this._objectToNode);
32
- }
33
-
34
- @log.method()
35
- async getRelationships({ label }: { label?: string }): Promise<Relationship[]> {
36
- const syntheticRefRelationships = (await this._getAllSchema())
37
- .filter((schema) => getSchemaTypename(schema) !== StoredSchema.typename)
38
- .flatMap((schema) => {
39
- const jsonSchema = toJsonSchema(schema);
40
- const relationships = Object.entries(jsonSchema.properties!).filter(([key, prop]) => isReference(prop));
41
-
42
- return relationships.map(([key, value]) => {
43
- const relationshipLabel = formatInferredRelationshipLabel(
44
- jsonSchema.typename ?? raise(new Error('Schema must have typename')),
45
- key,
46
- );
47
-
48
- return {
49
- label: relationshipLabel,
50
- schema,
51
- property: key,
52
- };
53
- });
54
- });
55
- const relationship = syntheticRefRelationships.find((r) => r.label === label);
56
- if (!relationship) {
57
- return []; // TODO(dmaretskyi): Handle real relationships.
58
- }
59
-
60
- const { objects } = await this._db.query(Filter.schema(relationship.schema)).run();
61
- return (
62
- await Promise.all(objects.map((object) => this._projectRefRelationship(object, relationship.property)))
63
- ).flat();
64
- }
65
-
66
- private async _getAllSchema(): Promise<S.Schema.AnyNoContext[]> {
67
- return [
68
- ...(await this._db.schemaRegistry.query().run()),
69
- // TODO(dmaretskyi): Remove once we can serialize recursive schema.
70
- ...this._db.graph.schemaRegistry.schemas.filter((s) => getSchemaTypename(s)?.startsWith('example.org')),
71
- ].filter((schema) => getSchemaTypename(schema) !== StoredSchema.typename);
72
- }
73
-
74
- private _objectToNode(object: ReactiveEchoObject<any>): Node {
75
- const { id, ...properties } = object;
76
- return {
77
- id,
78
- kind: 'node',
79
- label: formatNodeLabel(getSchemaTypename(getSchema(object)!)!),
80
- properties,
81
- };
82
- }
83
-
84
- private async _projectRefRelationship(object: ReactiveEchoObject<any>, prop: string): Promise<Relationship[]> {
85
- if (!object[prop]) {
86
- return [];
87
- }
88
-
89
- const value = Array.isArray(object[prop]) ? object[prop] : [object[prop]];
90
-
91
- return Promise.all(
92
- value.map(async (ref): Promise<Relationship> => {
93
- const target = await ref.load();
94
- return {
95
- id: `${object.id}-${prop}-${target.id}`,
96
- kind: 'relationship',
97
- label: formatInferredRelationshipLabel(getSchemaTypename(getSchema(object)!)!, prop),
98
- properties: {},
99
- source: this._objectToNode(object),
100
- target: this._objectToNode(target),
101
- };
102
- }),
103
- );
104
- }
105
- }
@@ -1,44 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { describe, test } from 'vitest';
6
-
7
- import { log } from '@dxos/log';
8
-
9
- import { createExecutionPlan } from './execution-plan';
10
- import { parseCypherQuery } from './parser';
11
-
12
- // log.config({ filter: 'debug' });
13
-
14
- describe('Execution Plan', () => {
15
- test('trivial', ({ expect }) => {
16
- const plan = createExecutionPlan(parseCypherQuery('MATCH (n:Person) RETURN n'));
17
- log('', { plan });
18
- expect(plan.steps.map((step) => step.type)).toEqual(['NodeScan', 'ProduceResults']);
19
- });
20
-
21
- test('complex query', ({ expect }) => {
22
- const plan = createExecutionPlan(
23
- parseCypherQuery(
24
- "MATCH (org:Org {name: 'DXOS'})-[:ORG_EMPLOYEES]->(c:Contact)<-[:TASK_ASSIGNEE]-(:Task)-[:TASK_PROJECT]->(p:Project {name: 'Composer'}) RETURN c.name",
25
- ),
26
- );
27
- log('', { plan });
28
- for (const step of plan.steps) {
29
- log('step', { step });
30
- }
31
- expect(plan.steps.map((step) => step.type)).toEqual([
32
- 'NodeScan',
33
- 'FilterByProperty',
34
- 'RelationshipScan',
35
- 'FilterByLabel',
36
- 'RelationshipScan',
37
- 'FilterByLabel',
38
- 'RelationshipScan',
39
- 'FilterByLabel',
40
- 'FilterByProperty',
41
- 'ProduceResults',
42
- ]);
43
- });
44
- });
@@ -1,208 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import type { JsonPath } from '@dxos/echo-schema';
6
- import { invariant } from '@dxos/invariant';
7
- import { log } from '@dxos/log';
8
-
9
- import type { GraphPatternConnector, MatchClause, ReturnClause, WhereClause } from './ast';
10
- import type { ParsedQuery } from './parser';
11
-
12
- export type VariableName = string & { __VariableName: never };
13
-
14
- export type ExecutionPlanStep =
15
- | {
16
- type: 'NodeScan';
17
- label: string;
18
- into: VariableName;
19
- }
20
- | {
21
- type: 'FilterByLabel';
22
- variable: VariableName;
23
- label: string;
24
- }
25
- | {
26
- type: 'FilterByProperty';
27
- variable: VariableName;
28
- property: JsonPath;
29
- value: unknown;
30
- }
31
- | {
32
- /**
33
- * Scans (anchor)-[relationshipInto:label]->(nodeInto).
34
- */
35
- type: 'RelationshipScan';
36
- label: string;
37
- anchor: VariableName;
38
- relationshipInto: VariableName;
39
- nodeInto: VariableName;
40
-
41
- /**
42
- * `in`: (anchor)<-[relationshipInto:label]-(nodeInto)
43
- * `out`: (anchor)-[relationshipInto:label]->(nodeInto)
44
- * `both`: (anchor)-[relationshipInto:label]-(nodeInto)
45
- */
46
- direction: 'in' | 'out' | 'both';
47
- }
48
- | {
49
- type: 'ProduceResults';
50
- fields: {
51
- name: string;
52
- variable: VariableName;
53
- path: JsonPath;
54
- }[];
55
- };
56
-
57
- export type ExecutionPlan = {
58
- steps: ExecutionPlanStep[];
59
- output: {
60
- fields: string[];
61
- };
62
- };
63
-
64
- export const createExecutionPlan = (query: ParsedQuery): ExecutionPlan => {
65
- return new ExecutionPlanBuilder().build(query);
66
- };
67
-
68
- class ExecutionPlanBuilder {
69
- private counter = 0;
70
-
71
- newVariable(): VariableName {
72
- return `anon_${this.counter++}` as VariableName;
73
- }
74
-
75
- build(query: ParsedQuery): ExecutionPlan {
76
- log('Creating execution plan for query', { query });
77
- return {
78
- steps: [
79
- ...this.createStepsForMatchClause(query.ast.matchClause),
80
- ...(query.ast.whereClause ? this.createStepsForWhereClause(query.ast.whereClause) : []),
81
- ...this.createStepsForReturnClause(query.ast.returnClause),
82
- ],
83
- output: {
84
- fields: this.getOutputFields(query.ast.returnClause),
85
- },
86
- };
87
- }
88
-
89
- createStepsForMatchClause(match: MatchClause): ExecutionPlanStep[] {
90
- invariant(match.pattern.segments.length > 0);
91
- const firstSegment = match.pattern.segments[0];
92
- invariant(firstSegment.astKind === 'NodePattern');
93
- let lastNodeVariable = (firstSegment.variable?.name as VariableName) ?? this.newVariable();
94
-
95
- const steps: ExecutionPlanStep[] = [];
96
- steps.push({
97
- type: 'NodeScan',
98
- label: firstSegment.label.name,
99
- into: lastNodeVariable,
100
- });
101
-
102
- if (firstSegment.properties) {
103
- for (const property of firstSegment.properties.properties) {
104
- steps.push({
105
- type: 'FilterByProperty',
106
- variable: lastNodeVariable,
107
- property: property.key.name as JsonPath,
108
- value: property.value.value,
109
- });
110
- }
111
- }
112
-
113
- for (let i = 1; i < match.pattern.segments.length; i++) {
114
- const relationshipSegment = match.pattern.segments[i++];
115
- invariant(relationshipSegment.astKind === 'RelationshipPattern');
116
- const nodeSegment = match.pattern.segments[i];
117
- invariant(nodeSegment.astKind === 'NodePattern');
118
- const leftSeparator = match.pattern.segments.separators[i - 2];
119
- const rightSeparator = match.pattern.segments.separators[i - 1];
120
- const direction = getDirection(leftSeparator.direction, rightSeparator.direction);
121
-
122
- const relationshipVariable = (relationshipSegment.variable?.name as VariableName) ?? this.newVariable();
123
- const nodeVariable = (nodeSegment.variable?.name as VariableName) ?? this.newVariable();
124
-
125
- steps.push({
126
- type: 'RelationshipScan',
127
- label: relationshipSegment.label.name,
128
- direction,
129
- anchor: lastNodeVariable,
130
- relationshipInto: relationshipVariable,
131
- nodeInto: nodeVariable,
132
- });
133
-
134
- if (relationshipSegment.properties) {
135
- for (const property of relationshipSegment.properties.properties) {
136
- steps.push({
137
- type: 'FilterByProperty',
138
- variable: relationshipVariable,
139
- property: property.key.name as JsonPath,
140
- value: property.value.value,
141
- });
142
- }
143
- }
144
- if (nodeSegment.label) {
145
- steps.push({
146
- type: 'FilterByLabel',
147
- variable: nodeVariable,
148
- label: nodeSegment.label.name,
149
- });
150
- }
151
- if (nodeSegment.properties) {
152
- for (const property of nodeSegment.properties.properties) {
153
- steps.push({
154
- type: 'FilterByProperty',
155
- variable: nodeVariable,
156
- property: property.key.name as JsonPath,
157
- value: property.value.value,
158
- });
159
- }
160
- }
161
-
162
- lastNodeVariable = nodeVariable;
163
- }
164
-
165
- return steps;
166
- }
167
-
168
- createStepsForWhereClause(where: WhereClause): ExecutionPlanStep[] {
169
- return [];
170
- }
171
-
172
- createStepsForReturnClause(returnClause: ReturnClause): ExecutionPlanStep[] {
173
- return [
174
- {
175
- type: 'ProduceResults',
176
- fields: returnClause.fields.map((field) => ({
177
- name: field.path.map((p) => p.name).join('_'),
178
- variable: field.path[0].name as VariableName,
179
- path:
180
- field.path.length > 1
181
- ? (field.path
182
- .slice(1)
183
- .map((p) => p.name)
184
- .join('.') as JsonPath)
185
- : ('$' as JsonPath),
186
- })),
187
- },
188
- ];
189
- }
190
-
191
- getOutputFields(returnClause: ReturnClause): string[] {
192
- return returnClause.fields.map((field) => field.path.map((p) => p.name).join('_'));
193
- }
194
- }
195
-
196
- const getDirection = (
197
- left: GraphPatternConnector['direction'],
198
- right: GraphPatternConnector['direction'],
199
- ): 'in' | 'out' | 'both' => {
200
- if (left === '-' && right === '->') {
201
- return 'out';
202
- } else if (left === '<-' && right === '-') {
203
- return 'in';
204
- } else if (left === '-' && right === '-') {
205
- return 'both';
206
- }
207
- throw new Error(`Invalid direction: ()${left}[]${right}()`);
208
- };
@@ -1,8 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- export * from './parser';
6
- export * from './query-executor';
7
- export * from './schema';
8
- export * from './echo-data-source';
@@ -1,10 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- declare module '#parjs' {
6
- import * as parjs from 'parjs';
7
- import * as parjsCombinators from 'parjs/combinators';
8
-
9
- export { parjsCombinators, parjs };
10
- }
@@ -1,10 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- // Workaround for https://github.com/vitest-dev/vitest/issues/7174.
6
- import type { Parjser } from 'parjs';
7
-
8
- import { parjsCombinators, parjs } from '#parjs';
9
-
10
- export { type Parjser, parjsCombinators, parjs };
@@ -1,19 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import type { CypherQuery } from './ast';
6
- import { cypherQuery } from './combinators';
7
-
8
- export type ParsedQuery = {
9
- ast: CypherQuery;
10
- };
11
-
12
- export const parseCypherQuery = (query: string): ParsedQuery => {
13
- const parseResult = cypherQuery.parse(query);
14
- if (parseResult.isOk) {
15
- return { ast: parseResult.value };
16
- } else {
17
- throw new Error(`Failed to parse query: ${parseResult}`);
18
- }
19
- };