@dxos/assistant 0.8.0 → 0.8.1-main.013e445

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 (99) hide show
  1. package/dist/lib/browser/chunk-BDMTBYIM.mjs +2285 -0
  2. package/dist/lib/browser/chunk-BDMTBYIM.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +328 -1206
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +17 -3
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/node/chunk-A44NGSCM.cjs +2296 -0
  9. package/dist/lib/node/chunk-A44NGSCM.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +335 -1206
  11. package/dist/lib/node/index.cjs.map +4 -4
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +40 -29
  14. package/dist/lib/node/testing/index.cjs.map +4 -4
  15. package/dist/lib/node-esm/chunk-J6DMSFSZ.mjs +2287 -0
  16. package/dist/lib/node-esm/chunk-J6DMSFSZ.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +328 -1206
  18. package/dist/lib/node-esm/index.mjs.map +4 -4
  19. package/dist/lib/node-esm/meta.json +1 -1
  20. package/dist/lib/node-esm/testing/index.mjs +17 -3
  21. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  22. package/dist/types/src/ai-service/defs.d.ts +8 -2
  23. package/dist/types/src/ai-service/defs.d.ts.map +1 -1
  24. package/dist/types/src/ai-service/edge-client.d.ts +19 -0
  25. package/dist/types/src/ai-service/edge-client.d.ts.map +1 -0
  26. package/dist/types/src/ai-service/index.d.ts +4 -1
  27. package/dist/types/src/ai-service/index.d.ts.map +1 -1
  28. package/dist/types/src/ai-service/message-collector.d.ts +88 -0
  29. package/dist/types/src/ai-service/message-collector.d.ts.map +1 -0
  30. package/dist/types/src/ai-service/ollama-client.d.ts +39 -0
  31. package/dist/types/src/ai-service/ollama-client.d.ts.map +1 -0
  32. package/dist/types/src/ai-service/parser.d.ts +11 -9
  33. package/dist/types/src/ai-service/parser.d.ts.map +1 -1
  34. package/dist/types/src/ai-service/service.d.ts +9 -0
  35. package/dist/types/src/ai-service/service.d.ts.map +1 -0
  36. package/dist/types/src/ai-service/stream.d.ts +2 -1
  37. package/dist/types/src/ai-service/stream.d.ts.map +1 -1
  38. package/dist/types/src/ai-service/testing/mock.d.ts +2 -2
  39. package/dist/types/src/ai-service/testing/mock.d.ts.map +1 -1
  40. package/dist/types/src/ai-service/types.d.ts +91 -157
  41. package/dist/types/src/ai-service/types.d.ts.map +1 -1
  42. package/dist/types/src/conversation/conversation.d.ts +11 -9
  43. package/dist/types/src/conversation/conversation.d.ts.map +1 -1
  44. package/dist/types/src/conversation/types.d.ts +1 -1
  45. package/dist/types/src/conversation/types.d.ts.map +1 -1
  46. package/dist/types/src/index.d.ts +1 -0
  47. package/dist/types/src/index.d.ts.map +1 -1
  48. package/dist/types/src/session/index.d.ts +2 -0
  49. package/dist/types/src/session/index.d.ts.map +1 -0
  50. package/dist/types/src/session/session.d.ts +215 -0
  51. package/dist/types/src/session/session.d.ts.map +1 -0
  52. package/dist/types/src/session/session.test.d.ts +2 -0
  53. package/dist/types/src/session/session.test.d.ts.map +1 -0
  54. package/dist/types/src/testing/index.d.ts +1 -0
  55. package/dist/types/src/testing/index.d.ts.map +1 -1
  56. package/dist/types/src/testing/ollama.d.ts +6 -0
  57. package/dist/types/src/testing/ollama.d.ts.map +1 -0
  58. package/dist/types/src/testing/query-promts.d.ts +1 -1
  59. package/dist/types/src/testing/query-promts.d.ts.map +1 -1
  60. package/dist/types/src/testing/test-data.d.ts +1 -1
  61. package/dist/types/src/testing/test-data.d.ts.map +1 -1
  62. package/dist/types/src/testing/test-schema.d.ts +1 -1
  63. package/dist/types/src/testing/test-schema.d.ts.map +1 -1
  64. package/package.json +17 -14
  65. package/src/ai-service/client.test.ts +100 -13
  66. package/src/ai-service/defs.ts +18 -3
  67. package/src/ai-service/{client.ts → edge-client.ts} +18 -26
  68. package/src/ai-service/index.ts +4 -1
  69. package/src/ai-service/message-collector.ts +84 -0
  70. package/src/ai-service/ollama-client.ts +499 -0
  71. package/src/ai-service/parser.ts +8 -2
  72. package/src/ai-service/service.ts +15 -0
  73. package/src/ai-service/stream.ts +5 -3
  74. package/src/ai-service/testing/mock.ts +7 -2
  75. package/src/ai-service/types.ts +3 -3
  76. package/src/bin/chat.ts +3 -3
  77. package/src/conversation/conversation.test.ts +5 -5
  78. package/src/conversation/conversation.ts +3 -2
  79. package/src/conversation/types.ts +1 -1
  80. package/src/index.ts +1 -0
  81. package/src/session/index.ts +5 -0
  82. package/src/session/session.test.ts +256 -0
  83. package/src/session/session.ts +369 -0
  84. package/src/testing/artifacts.test.ts +4 -4
  85. package/src/testing/index.ts +1 -0
  86. package/src/testing/object-extraction.test.ts +1 -1
  87. package/src/testing/ollama.ts +15 -0
  88. package/src/testing/query-promts.ts +1 -1
  89. package/src/testing/query.test.ts +4 -4
  90. package/src/testing/test-data.ts +1 -1
  91. package/src/testing/test-schema.ts +1 -1
  92. package/dist/lib/browser/chunk-AXUUNA7O.mjs +0 -565
  93. package/dist/lib/browser/chunk-AXUUNA7O.mjs.map +0 -7
  94. package/dist/lib/node/chunk-QPHGQINW.cjs +0 -577
  95. package/dist/lib/node/chunk-QPHGQINW.cjs.map +0 -7
  96. package/dist/lib/node-esm/chunk-GOVFOBIB.mjs +0 -567
  97. package/dist/lib/node-esm/chunk-GOVFOBIB.mjs.map +0 -7
  98. package/dist/types/src/ai-service/client.d.ts +0 -25
  99. package/dist/types/src/ai-service/client.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { Schema as S } from '@effect/schema';
1
+ import { Schema as S } from 'effect';
2
2
  import { type DataSource } from '../cypher';
3
3
  export declare const createCypherTool: (dataSource: DataSource, schemaTypes?: S.Schema.Any[]) => import("@dxos/artifact").Tool;
4
4
  export declare const createSystemPrompt: (schemaTypes: S.Schema.Any[]) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"query-promts.d.ts","sourceRoot":"","sources":["../../../../src/testing/query-promts.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,gBAAgB,CAAC;AAM7C,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAGlF,eAAO,MAAM,gBAAgB,eAAgB,UAAU,gBAAe,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,kCA0ChF,CAAC;AAEL,eAAO,MAAM,kBAAkB,gBAAiB,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,WAiB7D,CAAC"}
1
+ {"version":3,"file":"query-promts.d.ts","sourceRoot":"","sources":["../../../../src/testing/query-promts.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAC;AAMrC,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAGlF,eAAO,MAAM,gBAAgB,eAAgB,UAAU,gBAAe,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,kCA0ChF,CAAC;AAEL,eAAO,MAAM,kBAAkB,gBAAiB,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,WAiB7D,CAAC"}
@@ -1,4 +1,4 @@
1
- import { type Schema as S } from '@effect/schema';
1
+ import { type Schema as S } from 'effect';
2
2
  import type { EchoDatabase } from '@dxos/echo-db';
3
3
  import { type JsonSchemaType } from '@dxos/echo-schema';
4
4
  import { type DataSource, type Node, type Relationship } from '../cypher';
@@ -1 +1 @@
1
- {"version":3,"file":"test-data.d.ts","sourceRoot":"","sources":["../../../../src/testing/test-data.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,IAAI,CAAC,EAAE,MAAM,gBAAgB,CAAC;AAGlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAmD,KAAK,cAAc,EAAY,MAAM,mBAAmB,CAAC;AAInH,OAAO,EACL,KAAK,UAAU,EACf,KAAK,IAAI,EACT,KAAK,YAAY,EAGlB,MAAM,WAAW,CAAC;AAGnB,eAAO,MAAM,YAAY,OAAQ,YAAY,SAoH5C,CAAC;AAGF,eAAO,MAAM,cAAc,QAAO,cAuGjC,CAAC;AAEF,qBAAa,cAAe,YAAW,UAAU;IAC/C,OAAO,EAAE,MAAM,CACb,MAAM,EACN;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,OAAO,CAAC;KACf,CACF,CAAM;IAEP,MAAM,EAAE,MAAM,CACZ,MAAM,EACN;QACE,IAAI,EAAE,cAAc,CAAC;QACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;KACxB,CACF,CAAM;IAEP,KAAK,EAAE,IAAI,EAAE,CAAM;IACnB,aAAa,EAAE,YAAY,EAAE,CAAM;IAE7B,QAAQ,CAAC,EAAE,KAAK,EAAE,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAItC,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAIpD,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAsB7D,YAAY;CA0Eb"}
1
+ {"version":3,"file":"test-data.d.ts","sourceRoot":"","sources":["../../../../src/testing/test-data.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAC;AAG1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAmD,KAAK,cAAc,EAAY,MAAM,mBAAmB,CAAC;AAInH,OAAO,EACL,KAAK,UAAU,EACf,KAAK,IAAI,EACT,KAAK,YAAY,EAGlB,MAAM,WAAW,CAAC;AAGnB,eAAO,MAAM,YAAY,OAAQ,YAAY,SAoH5C,CAAC;AAGF,eAAO,MAAM,cAAc,QAAO,cAuGjC,CAAC;AAEF,qBAAa,cAAe,YAAW,UAAU;IAC/C,OAAO,EAAE,MAAM,CACb,MAAM,EACN;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,OAAO,CAAC;KACf,CACF,CAAM;IAEP,MAAM,EAAE,MAAM,CACZ,MAAM,EACN;QACE,IAAI,EAAE,cAAc,CAAC;QACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;KACxB,CACF,CAAM;IAEP,KAAK,EAAE,IAAI,EAAE,CAAM;IACnB,aAAa,EAAE,YAAY,EAAE,CAAM;IAE7B,QAAQ,CAAC,EAAE,KAAK,EAAE,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAItC,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAIpD,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAsB7D,YAAY;CA0Eb"}
@@ -1,4 +1,4 @@
1
- import { Schema as S } from '@effect/schema';
1
+ import { Schema as S } from 'effect';
2
2
  export declare const ObjectId: S.SchemaClass<string, string, never>;
3
3
  export declare const Contact: S.mutable<S.Struct<{
4
4
  id: S.SchemaClass<string, string, never>;
@@ -1 +1 @@
1
- {"version":3,"file":"test-schema.d.ts","sourceRoot":"","sources":["../../../../src/testing/test-schema.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,gBAAgB,CAAC;AAQ7C,eAAO,MAAM,QAAQ,sCAAyE,CAAC;AAE/F,eAAO,MAAM,OAAO;;;;GAahB,CAAC;AACL,MAAM,WAAW,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC;CAAG;AAEjE,eAAO,MAAM,OAAO;;;;GAahB,CAAC;AACL,MAAM,WAAW,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC;CAAG;AAEjE,eAAO,MAAM,IAAI;;;;;;;;;;;;;;GAeb,CAAC;AACL,MAAM,WAAW,IAAK,SAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC;CAAG;AAE3D,eAAO,MAAM,GAAG;;;;;;;;;;;;;GAcZ,CAAC;AACL,MAAM,WAAW,GAAI,SAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC;CAAG"}
1
+ {"version":3,"file":"test-schema.d.ts","sourceRoot":"","sources":["../../../../src/testing/test-schema.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAC;AAQrC,eAAO,MAAM,QAAQ,sCAAyE,CAAC;AAE/F,eAAO,MAAM,OAAO;;;;GAahB,CAAC;AACL,MAAM,WAAW,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC;CAAG;AAEjE,eAAO,MAAM,OAAO;;;;GAahB,CAAC;AACL,MAAM,WAAW,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC;CAAG;AAEjE,eAAO,MAAM,IAAI;;;;;;;;;;;;;;GAeb,CAAC;AACL,MAAM,WAAW,IAAK,SAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC;CAAG;AAE3D,eAAO,MAAM,GAAG;;;;;;;;;;;;;GAcZ,CAAC;AACL,MAAM,WAAW,GAAI,SAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC;CAAG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/assistant",
3
- "version": "0.8.0",
3
+ "version": "0.8.1-main.013e445",
4
4
  "description": "Natural language interface to DXOS",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -37,27 +37,30 @@
37
37
  "src"
38
38
  ],
39
39
  "dependencies": {
40
- "@effect/schema": "^0.75.5",
41
40
  "parjs": "^1.3.9",
42
41
  "parsimmon": "^1.18.1",
43
42
  "ulidx": "^2.3.0",
44
- "@dxos/debug": "0.8.0",
45
- "@dxos/context": "0.8.0",
46
- "@dxos/artifact": "0.8.0",
47
- "@dxos/echo-db": "0.8.0",
48
- "@dxos/async": "0.8.0",
49
- "@dxos/invariant": "0.8.0",
50
- "@dxos/echo-schema": "0.8.0",
51
- "@dxos/keys": "0.8.0",
52
- "@dxos/live-object": "0.8.0",
53
- "@dxos/log": "0.8.0",
54
- "@dxos/node-std": "0.8.0",
55
- "@dxos/util": "0.8.0"
43
+ "@dxos/artifact": "0.8.1-main.013e445",
44
+ "@dxos/async": "0.8.1-main.013e445",
45
+ "@dxos/echo-db": "0.8.1-main.013e445",
46
+ "@dxos/echo-schema": "0.8.1-main.013e445",
47
+ "@dxos/context": "0.8.1-main.013e445",
48
+ "@dxos/keys": "0.8.1-main.013e445",
49
+ "@dxos/live-object": "0.8.1-main.013e445",
50
+ "@dxos/debug": "0.8.1-main.013e445",
51
+ "@dxos/log": "0.8.1-main.013e445",
52
+ "@dxos/node-std": "0.8.1-main.013e445",
53
+ "@dxos/util": "0.8.1-main.013e445",
54
+ "@dxos/invariant": "0.8.1-main.013e445"
56
55
  },
57
56
  "devDependencies": {
58
57
  "@types/parsimmon": "^1.10.9",
58
+ "effect": "3.13.3",
59
59
  "inquirer": "^12.0.0"
60
60
  },
61
+ "peerDependencies": {
62
+ "effect": "^3.13.3"
63
+ },
61
64
  "publishConfig": {
62
65
  "access": "public"
63
66
  },
@@ -2,25 +2,27 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Schema as S } from '@effect/schema';
5
+ import { Schema as S } from 'effect';
6
6
  import { test, describe } from 'vitest';
7
7
 
8
- import { type Message, type Tool } from '@dxos/artifact';
9
- import { toJsonSchema, ObjectId } from '@dxos/echo-schema';
8
+ import { defineTool, Message, ToolResult, type Tool } from '@dxos/artifact';
9
+ import { toJsonSchema, ObjectId, createStatic } from '@dxos/echo-schema';
10
10
  import { invariant } from '@dxos/invariant';
11
11
  import { SpaceId } from '@dxos/keys';
12
12
  import { log } from '@dxos/log';
13
13
 
14
- import { AIServiceClientImpl } from './client';
15
- import { DEFAULT_LLM_MODEL } from './defs';
14
+ import { DEFAULT_EDGE_MODEL } from './defs';
15
+ import { AIServiceEdgeClient } from './edge-client';
16
+ import { OllamaClient } from './ollama-client';
17
+ import { MixedStreamParser } from './parser';
16
18
  import { ToolTypes } from './types';
17
- import { AI_SERVICE_ENDPOINT } from '../testing';
19
+ import { createTestOllamaClient, AI_SERVICE_ENDPOINT } from '../testing';
18
20
 
19
21
  // log.config({ filter: 'debug' });
20
22
 
21
23
  describe.skip('AI Service Client', () => {
22
24
  test('client generation', async () => {
23
- const client = new AIServiceClientImpl({
25
+ const client = new AIServiceEdgeClient({
24
26
  endpoint: AI_SERVICE_ENDPOINT.LOCAL,
25
27
  });
26
28
 
@@ -38,7 +40,7 @@ describe.skip('AI Service Client', () => {
38
40
  ]);
39
41
 
40
42
  const stream = await client.exec({
41
- model: DEFAULT_LLM_MODEL,
43
+ model: DEFAULT_EDGE_MODEL,
42
44
  spaceId,
43
45
  threadId,
44
46
  systemPrompt: 'You are a poet',
@@ -54,7 +56,7 @@ describe.skip('AI Service Client', () => {
54
56
  });
55
57
 
56
58
  test('tool calls', async () => {
57
- const client = new AIServiceClientImpl({
59
+ const client = new AIServiceEdgeClient({
58
60
  endpoint: AI_SERVICE_ENDPOINT.LOCAL,
59
61
  });
60
62
 
@@ -83,7 +85,7 @@ describe.skip('AI Service Client', () => {
83
85
 
84
86
  {
85
87
  const stream1 = await client.exec({
86
- model: DEFAULT_LLM_MODEL,
88
+ model: DEFAULT_EDGE_MODEL,
87
89
  spaceId,
88
90
  threadId,
89
91
  systemPrompt: 'You are a helpful assistant.',
@@ -117,7 +119,7 @@ describe.skip('AI Service Client', () => {
117
119
 
118
120
  {
119
121
  const stream2 = await client.exec({
120
- model: DEFAULT_LLM_MODEL,
122
+ model: DEFAULT_EDGE_MODEL,
121
123
  spaceId,
122
124
  threadId,
123
125
  systemPrompt: 'You are a helpful assistant.',
@@ -137,7 +139,7 @@ describe.skip('AI Service Client', () => {
137
139
  });
138
140
 
139
141
  test.skip('image generation', async () => {
140
- const client = new AIServiceClientImpl({
142
+ const client = new AIServiceEdgeClient({
141
143
  endpoint: AI_SERVICE_ENDPOINT.LOCAL,
142
144
  });
143
145
 
@@ -155,7 +157,7 @@ describe.skip('AI Service Client', () => {
155
157
  ]);
156
158
 
157
159
  const stream = await client.exec({
158
- model: DEFAULT_LLM_MODEL,
160
+ model: DEFAULT_EDGE_MODEL,
159
161
  spaceId,
160
162
  threadId,
161
163
  tools: [
@@ -176,3 +178,88 @@ describe.skip('AI Service Client', () => {
176
178
  log('full message', { message: await stream.complete() });
177
179
  });
178
180
  });
181
+
182
+ describe.skip('Ollama Client', () => {
183
+ test('basic', async (ctx) => {
184
+ const isRunning = await OllamaClient.isRunning();
185
+ if (!isRunning) {
186
+ ctx.skip();
187
+ }
188
+
189
+ const client = createTestOllamaClient();
190
+ const parser = new MixedStreamParser();
191
+
192
+ const messages = await parser.parse(
193
+ await client.exec({
194
+ prompt: createStatic(Message, {
195
+ role: 'user',
196
+ content: [{ type: 'text', text: 'Hello, world!' }],
197
+ }),
198
+ }),
199
+ );
200
+
201
+ log.info('messages', { messages });
202
+ });
203
+
204
+ test('tool calls', async (ctx) => {
205
+ const isRunning = await OllamaClient.isRunning();
206
+ if (!isRunning) {
207
+ ctx.skip();
208
+ }
209
+
210
+ const client = createTestOllamaClient({
211
+ tools: [
212
+ defineTool('test', {
213
+ name: 'encrypt',
214
+ description: 'Encrypt a message',
215
+ schema: S.Struct({
216
+ message: S.String.annotations({ description: 'The message to encrypt' }),
217
+ }),
218
+ execute: async ({ message }) => ToolResult.Success(message.split('').reverse().join('')),
219
+ }),
220
+ ],
221
+ });
222
+ const parser = new MixedStreamParser();
223
+ parser.streamEvent.on((event) => {
224
+ // log.info('event', { event });
225
+ });
226
+
227
+ const messages = await parser.parse(
228
+ await client.exec({
229
+ prompt: createStatic(Message, {
230
+ role: 'user',
231
+ content: [{ type: 'text', text: 'What is the encrypted message for "Hello, world!"' }],
232
+ }),
233
+ }),
234
+ );
235
+
236
+ log.info('messages', { messages });
237
+ });
238
+
239
+ test('text-to-image', async (ctx) => {
240
+ const isRunning = await OllamaClient.isRunning();
241
+ if (!isRunning) {
242
+ ctx.skip();
243
+ }
244
+
245
+ const client = createTestOllamaClient();
246
+ const parser = new MixedStreamParser();
247
+
248
+ const messages = await parser.parse(
249
+ await client.exec({
250
+ prompt: createStatic(Message, {
251
+ role: 'user',
252
+ content: [{ type: 'text', text: 'Generate an image of a cat' }],
253
+ }),
254
+ tools: [
255
+ {
256
+ name: 'text-to-image',
257
+ type: ToolTypes.TextToImage,
258
+ },
259
+ ],
260
+ }),
261
+ );
262
+
263
+ log.info('messages', { messages });
264
+ });
265
+ });
@@ -5,9 +5,9 @@
5
5
  // TODO(burdon): Share with Edge.
6
6
  // TODO(burdon): Move to service config retrieved by HTTP?
7
7
 
8
- export const DEFAULT_LLM_MODEL = '@anthropic/claude-3-5-sonnet-20241022';
8
+ export const DEFAULT_EDGE_MODEL = '@anthropic/claude-3-5-sonnet-20241022';
9
9
 
10
- export const DEFAULT_LLM_MODELS = [
10
+ export const DEFAULT_EDGE_MODELS = [
11
11
  // AI Gateway.
12
12
  // https://developers.cloudflare.com/ai-gateway
13
13
  '@anthropic/claude-3-5-haiku-20241022',
@@ -21,4 +21,19 @@ export const DEFAULT_LLM_MODELS = [
21
21
  '@ollama/llama-3-1-nemotron-70b-instruct',
22
22
  '@ollama/llama-3-1-nemotron-mini-4b-instruct',
23
23
  '@ollama/llama-3-2-3b',
24
- ];
24
+ ] as const;
25
+
26
+ // TODO(burdon): Config.
27
+ export const DEFAULT_OLLAMA_ENDPOINT = 'http://localhost:11434';
28
+
29
+ export const DEFAULT_OLLAMA_MODEL = 'llama3.2:1b';
30
+
31
+ /**
32
+ * https://ollama.com/library
33
+ */
34
+ export const DEFAULT_OLLAMA_MODELS = [
35
+ //
36
+ 'llama3.2:1b',
37
+ 'llama3:70b',
38
+ 'deepseek-r1:latest',
39
+ ] as const;
@@ -2,39 +2,32 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Schema as S } from '@effect/schema';
5
+ import { Schema as S } from 'effect';
6
6
 
7
7
  import { Message } from '@dxos/artifact';
8
- import { invariant } from '@dxos/invariant';
8
+ import { assertArgument, invariant } from '@dxos/invariant';
9
9
  import { log } from '@dxos/log';
10
10
 
11
- import { createGenerationStream, type GenerationStream } from './stream';
11
+ import type { AIServiceClient, GenerationStream } from './service';
12
+ import { createGenerationStream } from './stream';
12
13
  import { type GenerateRequest } from './types';
13
14
 
14
- export interface AIService {
15
- exec(request: GenerateRequest): Promise<GenerationStream>;
16
- }
17
-
18
- export interface AIServiceClient extends AIService {
19
- appendMessages(messages: Message[]): Promise<void>;
20
- }
21
-
22
- export type AIServiceClientParams = {
15
+ export type AIServiceEdgeClientOptions = {
23
16
  endpoint: string;
24
17
  };
25
18
 
26
- /**
27
- * Edge GPT client.
28
- */
29
- // TODO(burdon): Create mock.
30
- export class AIServiceClientImpl implements AIServiceClient {
19
+ export class AIServiceEdgeClient implements AIServiceClient {
31
20
  private readonly _endpoint: string;
32
21
 
33
- constructor({ endpoint }: AIServiceClientParams) {
22
+ constructor({ endpoint }: AIServiceEdgeClientOptions) {
34
23
  invariant(endpoint, 'endpoint is required');
35
24
  this._endpoint = endpoint;
36
25
  }
37
26
 
27
+ /**
28
+ * @deprecated
29
+ */
30
+ // TODO(burdon): Remove.
38
31
  async appendMessages(messages: Message[]): Promise<void> {
39
32
  const url = `${this._endpoint}/message`;
40
33
  const res = await fetch(url, {
@@ -54,19 +47,18 @@ export class AIServiceClientImpl implements AIServiceClient {
54
47
  * Process request and open message stream.
55
48
  */
56
49
  async exec(request: GenerateRequest): Promise<GenerationStream> {
57
- // TODO(dmaretskyi): Errors if tools are not provided.
58
- request = {
59
- tools: request.tools ?? [],
60
- ...request,
61
- };
62
-
63
- log.info('requesting', { endpoint: this._endpoint });
50
+ assertArgument(typeof request.model === 'string', 'model is required');
51
+ log('requesting', { endpoint: this._endpoint });
64
52
  const controller = new AbortController();
65
53
  const response = await fetch(`${this._endpoint}/generate`, {
66
54
  signal: controller.signal,
67
55
  method: 'POST',
68
56
  headers: { 'Content-Type': 'application/json' },
69
- body: JSON.stringify(request),
57
+ body: JSON.stringify({
58
+ // TODO(dmaretskyi): Errors if tools are not provided.
59
+ tools: request.tools ?? [],
60
+ ...request,
61
+ }),
70
62
  });
71
63
 
72
64
  invariant(response.body instanceof ReadableStream);
@@ -2,9 +2,12 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export * from './client';
6
5
  export * from './defs';
6
+ export * from './edge-client';
7
+ export * from './message-collector';
8
+ export * from './ollama-client';
7
9
  export * from './parser';
10
+ export * from './service';
8
11
  export * from './stream';
9
12
  export * from './transform';
10
13
  export * from './types';
@@ -0,0 +1,84 @@
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
+ }