@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,60 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { assertArgument, invariant } from '@dxos/invariant';
6
- import { log } from '@dxos/log';
7
-
8
- import type { AIServiceClient, GenerationStream } from './service';
9
- import { createGenerationStream } from './stream';
10
- import { type GenerateRequest, type GenerateResponse } from './types';
11
-
12
- export type AIServiceEdgeClientOptions = {
13
- endpoint: string;
14
- };
15
-
16
- export class AIServiceEdgeClient implements AIServiceClient {
17
- private readonly _endpoint: string;
18
-
19
- constructor({ endpoint }: AIServiceEdgeClientOptions) {
20
- invariant(endpoint, 'endpoint is required');
21
- this._endpoint = endpoint;
22
- }
23
-
24
- /**
25
- * Generate non-streaming response.
26
- */
27
- async exec(request: GenerateRequest): Promise<GenerateResponse> {
28
- throw new Error('Not implemented');
29
- }
30
-
31
- /**
32
- * Process request and open message stream.
33
- */
34
- async execStream(request: GenerateRequest): Promise<GenerationStream> {
35
- assertArgument(typeof request.model === 'string', 'model is required');
36
- log('requesting', { endpoint: this._endpoint });
37
- const controller = new AbortController();
38
- const response = await fetch(`${this._endpoint}/generate`, {
39
- signal: controller.signal,
40
- method: 'POST',
41
- headers: { 'Content-Type': 'application/json' },
42
- body: JSON.stringify({
43
- // TODO(dmaretskyi): Errors if tools are not provided.
44
- tools: request.tools ?? [],
45
- ...request,
46
- }),
47
- });
48
-
49
- if (!response.ok) {
50
- throw await parseErrorResponse(response);
51
- }
52
-
53
- invariant(response.body instanceof ReadableStream);
54
- return createGenerationStream(response, controller);
55
- }
56
- }
57
-
58
- const parseErrorResponse = async (response: Response): Promise<Error> => {
59
- throw new Error(`AI Service error: ${response.status} ${response.statusText} ${await response.text()}`);
60
- };
@@ -1,13 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- export * from './defs';
6
- export * from './edge-client';
7
- export * from './message-collector';
8
- export * from './ollama-client';
9
- export * from './parser';
10
- export * from './service';
11
- export * from './stream';
12
- export * from './transform';
13
- export * from './types';
@@ -1,84 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import type { Message } from '@dxos/artifact';
6
-
7
- import type { GenerationStreamEvent } from './types';
8
-
9
- export class MessageCollector {
10
- private _messages: Message[] = [];
11
- private _pendingMessage?: Message = undefined;
12
-
13
- public get messages() {
14
- return this._messages;
15
- }
16
-
17
- public get pendingMessage() {
18
- return this._pendingMessage;
19
- }
20
-
21
- push(event: GenerationStreamEvent) {
22
- switch (event.type) {
23
- case 'message_start':
24
- this._pendingMessage = event.message;
25
- break;
26
-
27
- case 'message_stop':
28
- if (this._pendingMessage) {
29
- this._messages.push(this._pendingMessage);
30
- this._pendingMessage = undefined;
31
- }
32
- break;
33
-
34
- case 'content_block_start':
35
- if (this._pendingMessage) {
36
- // Ensure the content array exists
37
- this._pendingMessage.content = this._pendingMessage.content || [];
38
- // Add the new content block at the specified index
39
- this._pendingMessage.content[event.index] = event.content;
40
- }
41
- break;
42
-
43
- case 'content_block_delta':
44
- if (this._pendingMessage && this._pendingMessage.content) {
45
- const block = this._pendingMessage.content[event.index];
46
- if (block && event.delta.type === 'text_delta' && block.type === 'text') {
47
- block.text = (block.text || '') + event.delta.text;
48
- }
49
- }
50
- break;
51
-
52
- case 'content_block_stop':
53
- // Mark the block as no longer pending if needed
54
- if (this._pendingMessage && this._pendingMessage.content) {
55
- const block = this._pendingMessage.content[event.index];
56
- if (block) {
57
- block.pending = false;
58
- }
59
- }
60
- break;
61
-
62
- case 'message_delta':
63
- // Apply any delta updates to the message
64
- if (this._pendingMessage && event.delta) {
65
- Object.assign(this._pendingMessage, event.delta);
66
- }
67
- break;
68
- }
69
- }
70
-
71
- pushMessage(message: Message) {
72
- this._messages.push(message);
73
- }
74
- }
75
-
76
- export function* emitMessageAsEvents(message: Message): Iterable<GenerationStreamEvent> {
77
- yield {
78
- type: 'message_start',
79
- message,
80
- };
81
- yield {
82
- type: 'message_stop',
83
- };
84
- }
@@ -1,506 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Schema } from 'effect';
6
-
7
- import { type MessageContentBlock, defineTool, type Tool, ToolResult } from '@dxos/artifact';
8
- import { ObjectId } from '@dxos/echo-schema';
9
- import { invariant } from '@dxos/invariant';
10
- import { log } from '@dxos/log';
11
-
12
- import { DEFAULT_OLLAMA_ENDPOINT } from './defs';
13
- import { MessageCollector, emitMessageAsEvents } from './message-collector';
14
- import { type AIServiceClient, type GenerationStream } from './service';
15
- import { GenerationStreamImpl } from './stream';
16
- import { ToolTypes, type GenerateRequest, type GenerateResponse, type GenerationStreamEvent } from './types';
17
- import { isToolUse, runTools } from '../session';
18
-
19
- export type OllamaClientParams = {
20
- endpoint?: string;
21
-
22
- /**
23
- * Tools that are executed within the client.
24
- */
25
- tools?: Tool[];
26
-
27
- /**
28
- * Override generation parameters.
29
- */
30
- // TODO(burdon): Why not just options?
31
- overrides?: {
32
- model?: string;
33
- temperature?: number;
34
- };
35
-
36
- /**
37
- * Maximum number of tool invocations in a single request that is allowed to run.
38
- * @default 3
39
- */
40
- maxToolInvocations?: number;
41
- };
42
-
43
- export class OllamaClient implements AIServiceClient {
44
- /**
45
- * Check if Ollama server is running and accessible.
46
- * @returns Promise that resolves to true if Ollama is running, false otherwise.
47
- */
48
- static async isRunning(): Promise<boolean> {
49
- try {
50
- const response = await fetch(`${DEFAULT_OLLAMA_ENDPOINT}/api/version`, {
51
- method: 'GET',
52
- headers: {
53
- 'Content-Type': 'application/json',
54
- },
55
- signal: AbortSignal.timeout(100),
56
- });
57
-
58
- return response.ok;
59
- } catch (error) {
60
- return false;
61
- }
62
- }
63
-
64
- private readonly _endpoint: string;
65
- private readonly _tools: Tool[];
66
- private readonly _modelOverride?: string;
67
- private readonly _temperatureOverride?: number;
68
- private readonly _maxToolInvocations: number;
69
-
70
- constructor({ endpoint, tools, overrides, maxToolInvocations }: OllamaClientParams = {}) {
71
- this._endpoint = endpoint ?? DEFAULT_OLLAMA_ENDPOINT;
72
- this._tools = tools ?? [];
73
- this._modelOverride = overrides?.model;
74
- this._temperatureOverride = overrides?.temperature;
75
- this._maxToolInvocations = maxToolInvocations ?? 3;
76
- }
77
-
78
- private _getEmbededTools(clientTools: Tool[]) {
79
- return [
80
- ...this._tools,
81
- ...clientTools
82
- .filter((tool) => tool.type !== undefined && WELL_KNOWN_TOOLS[tool.type])
83
- .map((tool) => WELL_KNOWN_TOOLS[tool.type!]),
84
- ];
85
- }
86
-
87
- private async *_generateStream(request: GenerateRequest, signal?: AbortSignal): AsyncIterable<GenerationStreamEvent> {
88
- invariant(request.prompt === undefined, 'Prompt must be in history');
89
-
90
- // Map DXOS request to Ollama API format.
91
- const ollamaRequest: OllamaRequest = {
92
- model: this._modelOverride ?? request.model ?? 'llama3',
93
- messages: [],
94
- stream: true,
95
- options: {
96
- temperature: this._temperatureOverride,
97
- },
98
- };
99
-
100
- // Add system message if provided.
101
- if (request.systemPrompt) {
102
- ollamaRequest.messages.push({
103
- role: 'system',
104
- content: request.systemPrompt,
105
- });
106
- }
107
-
108
- // Add history if provided.
109
- if (request.history?.length) {
110
- for (const message of request.history) {
111
- const role = message.role === 'assistant' ? 'assistant' : 'user';
112
-
113
- // Process message content.
114
- if (message.content.length === 0) {
115
- // Skip empty messages
116
- continue;
117
- }
118
-
119
- for (const content of message.content) {
120
- switch (content.type) {
121
- case 'text': {
122
- ollamaRequest.messages.push({
123
- role,
124
- content: content.text,
125
- });
126
- break;
127
- }
128
- case 'tool_use': {
129
- ollamaRequest.messages.push({
130
- role: 'assistant',
131
- content: '',
132
- tool_calls: [
133
- {
134
- function: {
135
- name: content.name,
136
- arguments: content.input as any,
137
- },
138
- },
139
- ],
140
- });
141
- break;
142
- }
143
- case 'tool_result': {
144
- ollamaRequest.messages.push({
145
- role: 'tool',
146
- content: JSON.stringify({
147
- type: 'tool_result',
148
- toolUseId: content.toolUseId,
149
- content: content.content,
150
- }),
151
- });
152
- break;
153
- }
154
- }
155
- }
156
- }
157
- }
158
-
159
- // Add tools if provided.
160
- if (request.tools?.length || this._tools.length) {
161
- const allTools = [...(request.tools ?? []), ...this._tools];
162
- const withWellKnownTools = allTools.map((tool) =>
163
- tool.type !== undefined && WELL_KNOWN_TOOLS[tool.type] ? WELL_KNOWN_TOOLS[tool.type] : tool,
164
- );
165
-
166
- if (withWellKnownTools.length > 0) {
167
- ollamaRequest.tools = withWellKnownTools.map((tool) => ({
168
- type: 'function',
169
- function: {
170
- name: tool.name,
171
- description: tool.description,
172
- parameters: {
173
- type: 'object',
174
- properties: tool.parameters?.properties,
175
- required: tool.parameters?.required,
176
- },
177
- },
178
- }));
179
- }
180
- }
181
-
182
- log('generate request', { history: request.history, prompt: request.prompt, ollamaRequest });
183
-
184
- const response = await fetch(`${this._endpoint}/api/chat`, {
185
- method: 'POST',
186
- headers: {
187
- 'Content-Type': 'application/json',
188
- },
189
- body: JSON.stringify(ollamaRequest),
190
- signal,
191
- });
192
-
193
- // TODO(burdon): Test if model is not found.
194
- if (!response.ok) {
195
- throw await parseErrorResponse(response);
196
- }
197
-
198
- if (!response.body) {
199
- throw new Error('Ollama API returned no response body');
200
- }
201
-
202
- // Create the stream
203
- const reader = response
204
- .body!.pipeThrough(new TextDecoderStream())
205
- .pipeThrough(new OllamaDecoderStream())
206
- .getReader();
207
-
208
- try {
209
- // Create a message ID.
210
- const messageId = ObjectId.random();
211
-
212
- // Send message_start event with proper message structure.
213
- yield {
214
- type: 'message_start',
215
- message: {
216
- id: messageId,
217
- role: 'assistant',
218
- content: [],
219
- },
220
- } as GenerationStreamEvent;
221
-
222
- // Initialize text content block.
223
- const textBlock: MessageContentBlock = {
224
- type: 'text',
225
- text: '',
226
- };
227
-
228
- let currentBlockIndex = 0;
229
-
230
- // Send content_block_start event.
231
- yield {
232
- type: 'content_block_start',
233
- index: currentBlockIndex,
234
- content: textBlock,
235
- } as GenerationStreamEvent;
236
-
237
- while (true) {
238
- const { done, value: data } = await reader.read();
239
-
240
- if (done) {
241
- break;
242
- }
243
-
244
- log('ollama data', { data });
245
-
246
- // Ollama sends chunks of text, we convert them to our event format.
247
- if (data.message?.content) {
248
- yield {
249
- type: 'content_block_delta',
250
- index: 0,
251
- delta: {
252
- type: 'text_delta',
253
- text: data.message.content,
254
- },
255
- } as GenerationStreamEvent;
256
- }
257
-
258
- // If tool usage is detected.
259
- if (data.message?.tool_calls && data.message?.tool_calls?.length > 0) {
260
- if (data.message.tool_calls.length > 1) {
261
- log.warn('Ollama returned multiple tool calls. Only the first one will be used.');
262
- }
263
-
264
- yield {
265
- type: 'content_block_stop',
266
- index: currentBlockIndex++,
267
- } as GenerationStreamEvent;
268
-
269
- yield {
270
- type: 'content_block_start',
271
- index: currentBlockIndex,
272
- content: {
273
- type: 'tool_use',
274
- id: ObjectId.random(),
275
- name: data.message.tool_calls[0].function.name,
276
- input: sanitizeToolArguments(data.message.tool_calls[0].function.arguments),
277
- },
278
- } as GenerationStreamEvent;
279
-
280
- yield {
281
- type: 'message_delta',
282
- delta: {
283
- stopReason: 'tool_use',
284
- },
285
- } as GenerationStreamEvent;
286
- }
287
- }
288
-
289
- // Send content_block_stop and message_stop events.
290
- yield {
291
- type: 'content_block_stop',
292
- index: currentBlockIndex,
293
- } as GenerationStreamEvent;
294
-
295
- yield {
296
- type: 'message_stop',
297
- } as GenerationStreamEvent;
298
- } finally {
299
- reader.releaseLock();
300
- }
301
- }
302
-
303
- /**
304
- * Generate non-streaming response.
305
- */
306
- async exec(request: GenerateRequest): Promise<GenerateResponse> {
307
- throw new Error('Not implemented');
308
- }
309
-
310
- async execStream(request: GenerateRequest): Promise<GenerationStream> {
311
- const controller = new AbortController();
312
-
313
- try {
314
- return new GenerationStreamImpl(
315
- controller,
316
- async function* (this: OllamaClient) {
317
- const collector = new MessageCollector();
318
-
319
- // Loop while running tools.
320
- let toolInvocations = 0;
321
- while (true) {
322
- for await (const event of this._generateStream(
323
- {
324
- ...request,
325
- history: [
326
- ...(request.history ?? []),
327
- ...(request.prompt ? [request.prompt] : []),
328
- ...collector.messages,
329
- ],
330
- prompt: undefined,
331
- },
332
- controller.signal,
333
- )) {
334
- collector.push(event);
335
- yield event;
336
- }
337
-
338
- if (
339
- collector.messages.length > 0 &&
340
- !isToolUse(collector.messages.at(-1)!, {
341
- onlyToolNames: this._getEmbededTools(request.tools ?? []).map((tool) => tool.name),
342
- })
343
- ) {
344
- break;
345
- }
346
-
347
- if (++toolInvocations > this._maxToolInvocations) {
348
- throw new Error('Maximum number of tool invocations reached');
349
- }
350
-
351
- const result = await runTools({
352
- message: collector.messages.at(-1)!,
353
- tools: this._getEmbededTools(request.tools ?? []),
354
- });
355
-
356
- switch (result.type) {
357
- case 'continue': {
358
- collector.pushMessage(result.message);
359
- yield* emitMessageAsEvents(result.message);
360
- break;
361
- }
362
- case 'break': {
363
- throw new Error('Tool use breaks not allowed');
364
- }
365
- }
366
- }
367
- }.bind(this),
368
- );
369
- } catch (error) {
370
- controller.abort();
371
- throw error;
372
- }
373
- }
374
- }
375
-
376
- const sanitizeToolArguments = (args: any) => {
377
- // TODO(dmaretskyi): Workaround for model bug.
378
- if (args.type === 'object' && typeof args.properties === 'object' && Array.isArray(args.required)) {
379
- return args.properties;
380
- }
381
-
382
- return args;
383
- };
384
-
385
- const SAMPLE_IMAGE_URL = 'https://images.nightcafe.studio/jobs/BNmcRhHCM1JRKoUtqSei/BNmcRhHCM1JRKoUtqSei--1--5b9rv.jpg';
386
-
387
- const WELL_KNOWN_TOOLS: Record<string, Tool> = {
388
- [ToolTypes.TextToImage]: defineTool('system', {
389
- name: 'text-to-image',
390
- description: 'Generate an image from a text prompt',
391
- schema: Schema.Struct({
392
- prompt: Schema.String.annotations({ description: 'The text prompt describing the image to generate' }),
393
- }),
394
- execute: async ({ prompt }) => {
395
- const image = await fetch(SAMPLE_IMAGE_URL).then(async (res) => Buffer.from(await res.arrayBuffer()));
396
-
397
- const imageBase64 = image.toString('base64');
398
- const id = ObjectId.random();
399
-
400
- return ToolResult.Success(`The generation was successful. Image ID: ${id} Prompt: ${prompt}`, [
401
- {
402
- type: 'image',
403
- id,
404
- source: {
405
- type: 'base64',
406
- mediaType: 'image/jpeg',
407
- data: imageBase64,
408
- },
409
- },
410
- ]);
411
- },
412
- }),
413
- };
414
-
415
- type OllamaMessage = {
416
- role: 'system' | 'user' | 'assistant' | 'tool';
417
- content: string;
418
- tool_calls?: Array<{
419
- function: {
420
- name: string;
421
- arguments: string;
422
- };
423
- }>;
424
- };
425
-
426
- type OllamaRequest = {
427
- model: string;
428
- messages: Array<OllamaMessage>;
429
- stream: boolean;
430
- options?: {
431
- temperature?: number;
432
- };
433
- tools?: Array<{
434
- type: 'function';
435
- function: {
436
- name: string;
437
- description?: string;
438
- parameters?: any;
439
- };
440
- }>;
441
- };
442
-
443
- type OllamaResponseData = {
444
- message?: OllamaMessage;
445
- };
446
-
447
- class OllamaDecoderStream extends TransformStream<string, OllamaResponseData> {
448
- private _buffer = '';
449
-
450
- constructor() {
451
- super({
452
- transform: (chunk, controller) => {
453
- this._buffer += chunk;
454
- const lines = this._buffer.split('\n');
455
- this._buffer = lines.pop() || '';
456
- for (const line of lines) {
457
- controller.enqueue(JSON.parse(line.trim()));
458
- }
459
- },
460
- flush: (controller) => {
461
- this._buffer = this._buffer.trim();
462
- if (this._buffer.length > 0) {
463
- controller.enqueue(JSON.parse(this._buffer));
464
- }
465
- },
466
- });
467
- }
468
- }
469
-
470
- class ModelDoesNotSupportToolsError extends Schema.TaggedError<ModelDoesNotSupportToolsError>()(
471
- 'ModelDoesNotSupportToolsError',
472
- {
473
- model: Schema.String,
474
- },
475
- ) {}
476
-
477
- class ModelNotFoundError extends Schema.TaggedError<ModelNotFoundError>()('ModelNotFoundError', {
478
- model: Schema.String,
479
- }) {}
480
-
481
- const parseOllamaError = (error: string): Error => {
482
- {
483
- const match = error.match(/^([^']+) does not support tools$/);
484
- if (match) {
485
- return new ModelDoesNotSupportToolsError({ model: match[1] });
486
- }
487
- }
488
-
489
- {
490
- const match = error.match(/^model "([^"]+)" not found, try pulling it first$/);
491
- if (match) {
492
- return new ModelNotFoundError({ model: match[1] });
493
- }
494
- }
495
-
496
- throw new Error(`Ollama API error: ${error}`);
497
- };
498
-
499
- const parseErrorResponse = async (response: Response): Promise<Error> => {
500
- if (response.headers.get('content-type')?.includes('application/json')) {
501
- const body = await response.json();
502
- return parseOllamaError(body.error);
503
- }
504
-
505
- throw new Error(`Ollama API error: ${response.status} ${response.statusText} ${await response.text()}`);
506
- };