@dxos/functions 0.8.3 → 0.8.4-main.f9ba587

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 (69) hide show
  1. package/dist/lib/browser/bundler/index.mjs +21 -10
  2. package/dist/lib/browser/bundler/index.mjs.map +3 -3
  3. package/dist/lib/browser/{chunk-WEFZUEL2.mjs → chunk-54U464M4.mjs} +79 -19
  4. package/dist/lib/browser/chunk-54U464M4.mjs.map +7 -0
  5. package/dist/lib/browser/edge/index.mjs +2 -2
  6. package/dist/lib/browser/index.mjs +20 -14
  7. package/dist/lib/browser/index.mjs.map +3 -3
  8. package/dist/lib/browser/meta.json +1 -1
  9. package/dist/lib/browser/testing/index.mjs +58 -7
  10. package/dist/lib/browser/testing/index.mjs.map +4 -4
  11. package/dist/lib/node-esm/bundler/index.mjs +21 -10
  12. package/dist/lib/node-esm/bundler/index.mjs.map +3 -3
  13. package/dist/lib/node-esm/{chunk-LIYPMWNQ.mjs → chunk-XDSX35BS.mjs} +79 -19
  14. package/dist/lib/node-esm/chunk-XDSX35BS.mjs.map +7 -0
  15. package/dist/lib/node-esm/edge/index.mjs +2 -2
  16. package/dist/lib/node-esm/index.mjs +20 -14
  17. package/dist/lib/node-esm/index.mjs.map +3 -3
  18. package/dist/lib/node-esm/meta.json +1 -1
  19. package/dist/lib/node-esm/testing/index.mjs +58 -7
  20. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  21. package/dist/types/src/bundler/bundler.d.ts +1 -2
  22. package/dist/types/src/bundler/bundler.d.ts.map +1 -1
  23. package/dist/types/src/executor/executor.d.ts.map +1 -1
  24. package/dist/types/src/handler.d.ts +3 -6
  25. package/dist/types/src/handler.d.ts.map +1 -1
  26. package/dist/types/src/schema.d.ts +3 -3
  27. package/dist/types/src/services/credentials.d.ts +1 -1
  28. package/dist/types/src/services/credentials.d.ts.map +1 -1
  29. package/dist/types/src/services/database.d.ts +5 -1
  30. package/dist/types/src/services/database.d.ts.map +1 -1
  31. package/dist/types/src/services/index.d.ts +1 -0
  32. package/dist/types/src/services/index.d.ts.map +1 -1
  33. package/dist/types/src/services/queues.d.ts +2 -2
  34. package/dist/types/src/services/queues.d.ts.map +1 -1
  35. package/dist/types/src/services/service-container.d.ts +3 -1
  36. package/dist/types/src/services/service-container.d.ts.map +1 -1
  37. package/dist/types/src/services/tool-resolver.d.ts +14 -0
  38. package/dist/types/src/services/tool-resolver.d.ts.map +1 -0
  39. package/dist/types/src/testing/services.d.ts +67 -9
  40. package/dist/types/src/testing/services.d.ts.map +1 -1
  41. package/dist/types/src/translations.d.ts +9 -9
  42. package/dist/types/src/translations.d.ts.map +1 -1
  43. package/dist/types/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +29 -26
  45. package/src/bundler/bundler.test.ts +1 -1
  46. package/src/bundler/bundler.ts +26 -4
  47. package/src/executor/executor.ts +15 -8
  48. package/src/handler.ts +6 -6
  49. package/src/services/credentials.ts +1 -1
  50. package/src/services/database.ts +23 -1
  51. package/src/services/index.ts +1 -0
  52. package/src/services/queues.ts +9 -4
  53. package/src/services/service-container.ts +21 -3
  54. package/src/services/tool-resolver.ts +31 -0
  55. package/src/testing/services.ts +156 -14
  56. package/src/translations.ts +4 -4
  57. package/dist/lib/browser/chunk-WEFZUEL2.mjs.map +0 -7
  58. package/dist/lib/node/bundler/index.cjs +0 -260
  59. package/dist/lib/node/bundler/index.cjs.map +0 -7
  60. package/dist/lib/node/chunk-IJAE7FZK.cjs +0 -320
  61. package/dist/lib/node/chunk-IJAE7FZK.cjs.map +0 -7
  62. package/dist/lib/node/edge/index.cjs +0 -94
  63. package/dist/lib/node/edge/index.cjs.map +0 -7
  64. package/dist/lib/node/index.cjs +0 -522
  65. package/dist/lib/node/index.cjs.map +0 -7
  66. package/dist/lib/node/meta.json +0 -1
  67. package/dist/lib/node/testing/index.cjs +0 -43
  68. package/dist/lib/node/testing/index.cjs.map +0 -7
  69. package/dist/lib/node-esm/chunk-LIYPMWNQ.mjs.map +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/functions",
3
- "version": "0.8.3",
3
+ "version": "0.8.4-main.f9ba587",
4
4
  "description": "Functions API and runtime.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -9,11 +9,6 @@
9
9
  "sideEffects": true,
10
10
  "type": "module",
11
11
  "exports": {
12
- ".": {
13
- "types": "./dist/types/src/index.d.ts",
14
- "browser": "./dist/lib/browser/index.mjs",
15
- "node": "./dist/lib/node-esm/index.mjs"
16
- },
17
12
  "./bundler": {
18
13
  "types": "./dist/types/src/bundler/index.d.ts",
19
14
  "browser": "./dist/lib/browser/bundler/index.mjs",
@@ -24,6 +19,11 @@
24
19
  "browser": "./dist/lib/browser/edge/index.mjs",
25
20
  "node": "./dist/lib/node-esm/edge/index.mjs"
26
21
  },
22
+ ".": {
23
+ "types": "./dist/types/src/index.d.ts",
24
+ "browser": "./dist/lib/browser/index.mjs",
25
+ "node": "./dist/lib/node-esm/index.mjs"
26
+ },
27
27
  "./testing": {
28
28
  "types": "./dist/types/src/testing/index.d.ts",
29
29
  "browser": "./dist/lib/browser/testing/index.mjs",
@@ -47,38 +47,41 @@
47
47
  "src"
48
48
  ],
49
49
  "dependencies": {
50
+ "@effect/platform": "0.88.0",
50
51
  "@preact/signals-core": "^1.9.0",
51
52
  "cron": "^3.1.6",
52
53
  "cron-schedule": "^5.0.4",
53
- "effect": "3.14.21",
54
+ "effect": "3.16.13",
54
55
  "esbuild-wasm": "^0.16.14",
55
56
  "express": "^4.19.2",
56
57
  "get-port-please": "^3.1.1",
58
+ "i18next": "^24.2.1",
57
59
  "iso-did": "^1.6.0",
58
60
  "ws": "^8.14.2",
59
- "@dxos/ai": "0.8.3",
60
- "@dxos/client": "0.8.3",
61
- "@dxos/async": "0.8.3",
62
- "@dxos/crypto": "0.8.3",
63
- "@dxos/echo": "0.8.3",
64
- "@dxos/context": "0.8.3",
65
- "@dxos/echo-protocol": "0.8.3",
66
- "@dxos/echo-db": "0.8.3",
67
- "@dxos/echo-schema": "0.8.3",
68
- "@dxos/edge-client": "0.8.3",
69
- "@dxos/invariant": "0.8.3",
70
- "@dxos/keys": "0.8.3",
71
- "@dxos/live-object": "0.8.3",
72
- "@dxos/log": "0.8.3",
73
- "@dxos/node-std": "0.8.3",
74
- "@dxos/protocols": "0.8.3",
75
- "@dxos/schema": "0.8.3",
76
- "@dxos/util": "0.8.3"
61
+ "@dxos/ai": "0.8.4-main.f9ba587",
62
+ "@dxos/async": "0.8.4-main.f9ba587",
63
+ "@dxos/client": "0.8.4-main.f9ba587",
64
+ "@dxos/context": "0.8.4-main.f9ba587",
65
+ "@dxos/crypto": "0.8.4-main.f9ba587",
66
+ "@dxos/echo": "0.8.4-main.f9ba587",
67
+ "@dxos/echo-db": "0.8.4-main.f9ba587",
68
+ "@dxos/echo-protocol": "0.8.4-main.f9ba587",
69
+ "@dxos/echo-schema": "0.8.4-main.f9ba587",
70
+ "@dxos/edge-client": "0.8.4-main.f9ba587",
71
+ "@dxos/effect": "0.8.4-main.f9ba587",
72
+ "@dxos/keys": "0.8.4-main.f9ba587",
73
+ "@dxos/invariant": "0.8.4-main.f9ba587",
74
+ "@dxos/live-object": "0.8.4-main.f9ba587",
75
+ "@dxos/log": "0.8.4-main.f9ba587",
76
+ "@dxos/node-std": "0.8.4-main.f9ba587",
77
+ "@dxos/protocols": "0.8.4-main.f9ba587",
78
+ "@dxos/schema": "0.8.4-main.f9ba587",
79
+ "@dxos/util": "0.8.4-main.f9ba587"
77
80
  },
78
81
  "devDependencies": {
79
82
  "@types/express": "^4.17.17",
80
83
  "@types/ws": "^7.4.0",
81
- "@dxos/agent": "0.8.3"
84
+ "@dxos/agent": "0.8.4-main.f9ba587"
82
85
  },
83
86
  "publishConfig": {
84
87
  "access": "public"
@@ -37,7 +37,7 @@ describe('Bundler', () => {
37
37
  expect(result.error).to.not.exist;
38
38
  });
39
39
 
40
- // TODO(dmaretskyi): Flaky on CI: https://cloud.nx.app/runs/Hjcifa8Ccq/task/plugin-script%3Atest
40
+ // TODO(dmaretskyi): Flaky on CI.
41
41
  test.skip('HTTPS Import', async () => {
42
42
  const bundler = new Bundler({ platform: 'node', sandboxedModules: [], remoteModules: {} });
43
43
  const result = await bundler.bundle({
@@ -2,10 +2,12 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type BuildOptions } from 'esbuild';
6
- import { build, initialize, type BuildResult, type Plugin } from 'esbuild-wasm';
5
+ import { FetchHttpClient, HttpClient } from '@effect/platform';
6
+ import { Duration, Effect, pipe, Schedule } from 'effect';
7
+ import { type BuildOptions, type Loader, build, initialize, type BuildResult, type Plugin } from 'esbuild-wasm';
7
8
 
8
9
  import { subtleCrypto } from '@dxos/crypto';
10
+ import { runAndForwardErrors } from '@dxos/effect';
9
11
  import { invariant } from '@dxos/invariant';
10
12
  import { log } from '@dxos/log';
11
13
 
@@ -242,6 +244,9 @@ const analyzeSourceFileImports = (code: string): ParsedImport[] => {
242
244
  });
243
245
  };
244
246
 
247
+ const MAX_RETRIES = 5;
248
+ const INITIAL_DELAY = 1_000;
249
+
245
250
  const httpPlugin: Plugin = {
246
251
  name: 'http',
247
252
  setup: (build) => {
@@ -263,8 +268,25 @@ const httpPlugin: Plugin = {
263
268
  // When a URL is loaded, we want to actually download the content from the internet.
264
269
  // This has just enough logic to be able to handle the example import from unpkg.com but in reality this would probably need to be more complex.
265
270
  build.onLoad({ filter: /.*/, namespace: 'http-url' }, async (args) => {
266
- const response = await fetch(args.path);
267
- return { contents: await response.text(), loader: 'jsx' };
271
+ return Effect.gen(function* () {
272
+ const response = yield* HttpClient.get(args.path);
273
+ if (response.status !== 200) {
274
+ throw new Error(`failed to fetch: ${response.status}`);
275
+ }
276
+
277
+ const text = yield* response.text;
278
+ return { contents: text, loader: 'jsx' as Loader };
279
+ }).pipe(
280
+ Effect.retry(
281
+ pipe(
282
+ Schedule.exponential(Duration.millis(INITIAL_DELAY)),
283
+ Schedule.jittered,
284
+ Schedule.intersect(Schedule.recurs(MAX_RETRIES - 1)),
285
+ ),
286
+ ),
287
+ Effect.provide(FetchHttpClient.layer),
288
+ runAndForwardErrors,
289
+ );
268
290
  });
269
291
  },
270
292
  };
@@ -5,9 +5,10 @@
5
5
  import { Effect, Schema } from 'effect';
6
6
 
7
7
  import type { SpaceId } from '@dxos/client/echo';
8
+ import { runAndForwardErrors } from '@dxos/effect';
8
9
 
9
10
  import type { FunctionContext, FunctionDefinition } from '../handler';
10
- import type { ServiceContainer } from '../services';
11
+ import type { ServiceContainer, Services } from '../services';
11
12
 
12
13
  export class FunctionExecutor {
13
14
  constructor(private readonly _services: ServiceContainer) {}
@@ -32,16 +33,22 @@ export class FunctionExecutor {
32
33
  },
33
34
  };
34
35
 
35
- const result = await fnDef.handler({ context, data: input });
36
-
37
- // Assert output matches schema
38
- const assertOutput = fnDef.outputSchema?.pipe(Schema.asserts);
39
- (assertOutput as any)(result);
36
+ const result = fnDef.handler({ context, data: input });
40
37
 
38
+ let data: unknown;
41
39
  if (Effect.isEffect(result)) {
42
- return Effect.runPromise(result as any);
40
+ data = await (result as Effect.Effect<unknown, unknown, Services>).pipe(
41
+ Effect.provide(this._services.createLayer()),
42
+ runAndForwardErrors,
43
+ );
44
+ } else {
45
+ data = await result;
43
46
  }
44
47
 
45
- return result as any;
48
+ // Assert output matches schema
49
+ const assertOutput = fnDef.outputSchema?.pipe(Schema.asserts);
50
+ (assertOutput as any)(data);
51
+
52
+ return data as any;
46
53
  }
47
54
  }
package/src/handler.ts CHANGED
@@ -6,11 +6,13 @@ import { Schema, type Context, type Effect } from 'effect';
6
6
 
7
7
  import { type AiServiceClient } from '@dxos/ai';
8
8
  // import { type Space } from '@dxos/client/echo';
9
- import type { CoreDatabase, EchoDatabase } from '@dxos/echo-db';
9
+ import type { EchoDatabase } from '@dxos/echo-db';
10
10
  import { type HasId } from '@dxos/echo-schema';
11
11
  import { type SpaceId, type DXN } from '@dxos/keys';
12
12
  import { type QueryResult } from '@dxos/protocols';
13
13
 
14
+ import type { Services } from './services';
15
+
14
16
  // TODO(burdon): Model after http request. Ref Lambda/OpenFaaS.
15
17
  // https://docs.aws.amazon.com/lambda/latest/dg/typescript-handler.html
16
18
  // https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/#functions
@@ -31,7 +33,7 @@ export type FunctionHandler<TData = {}, TOutput = any> = (params: {
31
33
  * This will be the payload from the trigger or other data passed into the function in a workflow.
32
34
  */
33
35
  data: TData;
34
- }) => TOutput | Promise<TOutput> | Effect.Effect<TOutput, any>;
36
+ }) => TOutput | Promise<TOutput> | Effect.Effect<TOutput, any, Services>;
35
37
 
36
38
  /**
37
39
  * Function context.
@@ -74,11 +76,9 @@ export interface QueuesAPI {
74
76
  */
75
77
  export interface SpaceAPI {
76
78
  get id(): SpaceId;
77
- /**
78
- * @deprecated
79
- */
80
- get crud(): CoreDatabase;
79
+
81
80
  get db(): EchoDatabase;
81
+
82
82
  // TODO(dmaretskyi): Align with echo api --- queues.get(id).append(items);
83
83
  get queues(): QueuesAPI;
84
84
  }
@@ -10,7 +10,7 @@ type CredentialQuery = {
10
10
 
11
11
  // TODO(dmaretskyi): Unify with other apis.
12
12
  // packages/sdk/schema/src/common/access-token.ts
13
- type ServiceCredential = {
13
+ export type ServiceCredential = {
14
14
  service: string;
15
15
 
16
16
  // TODO(dmaretskyi): Build out.
@@ -2,9 +2,11 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Context, Layer } from 'effect';
5
+ import { Context, Effect, Layer } from 'effect';
6
6
 
7
+ import type { Obj, Ref, Relation } from '@dxos/echo';
7
8
  import type { EchoDatabase } from '@dxos/echo-db';
9
+ import type { DXN } from '@dxos/keys';
8
10
 
9
11
  export class DatabaseService extends Context.Tag('DatabaseService')<
10
12
  DatabaseService,
@@ -25,4 +27,24 @@ export class DatabaseService extends Context.Tag('DatabaseService')<
25
27
  },
26
28
  };
27
29
  };
30
+
31
+ static resolve: (dxn: DXN) => Effect.Effect<Obj.Any | Relation.Any, Error, DatabaseService> = Effect.fn(
32
+ function* (dxn) {
33
+ const { db } = yield* DatabaseService;
34
+ return yield* Effect.tryPromise({
35
+ try: () =>
36
+ db.graph.createRefResolver({ context: { space: db.spaceId } }).resolve(dxn) as Promise<
37
+ Obj.Any | Relation.Any
38
+ >,
39
+ catch: (error) => error as Error,
40
+ });
41
+ },
42
+ );
43
+
44
+ static loadRef: <T>(ref: Ref.Ref<T>) => Effect.Effect<T, Error, never> = Effect.fn(function* (ref) {
45
+ return yield* Effect.tryPromise({
46
+ try: () => ref.load(),
47
+ catch: (error) => error as Error,
48
+ });
49
+ });
28
50
  }
@@ -10,3 +10,4 @@ export * from './credentials';
10
10
  export * from './tracing';
11
11
  export * from './event-logger';
12
12
  export * from './function-call-service';
13
+ export * from './tool-resolver';
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { Context, Layer } from 'effect';
6
6
 
7
- import type { Queue, QueueFactory } from '@dxos/echo-db';
7
+ import type { Queue, QueueAPI, QueueFactory } from '@dxos/echo-db';
8
8
 
9
9
  export class QueueService extends Context.Tag('QueueService')<
10
10
  QueueService,
@@ -12,7 +12,7 @@ export class QueueService extends Context.Tag('QueueService')<
12
12
  /**
13
13
  * API to access the queues.
14
14
  */
15
- readonly queues: QueueFactory;
15
+ readonly queues: QueueAPI;
16
16
 
17
17
  /**
18
18
  * The queue that is used to store the context of the current research.
@@ -22,8 +22,13 @@ export class QueueService extends Context.Tag('QueueService')<
22
22
  }
23
23
  >() {
24
24
  static notAvailable = Layer.succeed(QueueService, {
25
- get queues(): QueueFactory {
26
- throw new Error('Queues not available');
25
+ queues: {
26
+ get(dxn) {
27
+ throw new Error('Queues not available');
28
+ },
29
+ create() {
30
+ throw new Error('Queues not available');
31
+ },
27
32
  },
28
33
  contextQueue: undefined,
29
34
  });
@@ -10,6 +10,7 @@ import { DatabaseService } from './database';
10
10
  import { EventLogger } from './event-logger';
11
11
  import { FunctionCallService } from './function-call-service';
12
12
  import { QueueService } from './queues';
13
+ import { ToolResolverService } from './tool-resolver';
13
14
  import { TracingService } from './tracing';
14
15
 
15
16
  /**
@@ -23,6 +24,7 @@ export interface ServiceTagRecord {
23
24
  functionCallService: FunctionCallService;
24
25
  tracing: TracingService;
25
26
  queues: QueueService;
27
+ toolResolver: ToolResolverService;
26
28
  }
27
29
 
28
30
  /**
@@ -45,6 +47,7 @@ const SERVICE_MAPPING: Record<string, keyof ServiceRecord> = {
45
47
  [FunctionCallService.key]: 'functionCallService',
46
48
  [QueueService.key]: 'queues',
47
49
  [TracingService.key]: 'tracing',
50
+ [ToolResolverService.key]: 'toolResolver',
48
51
  };
49
52
 
50
53
  export const SERVICE_TAGS: Context.Tag<any, any>[] = [
@@ -74,13 +77,14 @@ export class ServiceContainer {
74
77
  return this;
75
78
  }
76
79
 
77
- getService<T extends Context.Tag<any, any>>(tag: T): Context.Tag.Service<T> {
80
+ getService<Id, T>(tag: Context.Tag<Id, T>): T {
78
81
  const serviceKey = SERVICE_MAPPING[tag.key];
79
82
  const service = serviceKey != null ? this._services[serviceKey] : undefined;
80
83
  if (!service) {
81
84
  throw new Error(`Service not available: ${tag.key}`);
82
85
  }
83
- return service as Context.Tag.Service<T>;
86
+
87
+ return service as T;
84
88
  }
85
89
 
86
90
  clone(): ServiceContainer {
@@ -103,7 +107,21 @@ export class ServiceContainer {
103
107
  FunctionCallService,
104
108
  this._services.functionCallService ?? FunctionCallService.mock(),
105
109
  );
110
+ const toolResolver = Layer.succeed(
111
+ ToolResolverService,
112
+ this._services.toolResolver ?? ToolResolverService.notAvailable,
113
+ );
106
114
 
107
- return Layer.mergeAll(ai, credentials, database, queues, tracing, eventLogger, functionCallService);
115
+ return Layer.mergeAll(
116
+ //
117
+ ai,
118
+ credentials,
119
+ database,
120
+ queues,
121
+ tracing,
122
+ eventLogger,
123
+ functionCallService,
124
+ toolResolver,
125
+ );
108
126
  }
109
127
  }
@@ -0,0 +1,31 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Context } from 'effect';
6
+
7
+ import { type ToolResolver } from '@dxos/ai';
8
+
9
+ export class ToolResolverService extends Context.Tag('ToolResolverService')<
10
+ ToolResolverService,
11
+ {
12
+ /**
13
+ * Tool resolver.
14
+ */
15
+ readonly toolResolver: ToolResolver;
16
+ }
17
+ >() {
18
+ static notAvailable: Context.Tag.Service<ToolResolverService> = {
19
+ toolResolver: {
20
+ resolve: async (id: string) => {
21
+ throw new Error('Tool resolver not available');
22
+ },
23
+ },
24
+ };
25
+
26
+ static make = (toolResolver: ToolResolver): Context.Tag.Service<ToolResolverService> => {
27
+ return {
28
+ toolResolver,
29
+ };
30
+ };
31
+ }
@@ -4,29 +4,171 @@
4
4
 
5
5
  import { type Context } from 'effect';
6
6
 
7
- import type { AiServiceClient } from '@dxos/ai';
8
- import type { QueueFactory } from '@dxos/echo-db';
7
+ import { type AiServiceEdgeClientOptions, EdgeAiServiceClient, type AiServiceClient, ToolRegistry } from '@dxos/ai';
8
+ import { AI_SERVICE_ENDPOINT, createTestAiServiceClient } from '@dxos/ai/testing';
9
+ import type { Space } from '@dxos/client/echo';
10
+ import type { EchoDatabase, QueueFactory } from '@dxos/echo-db';
11
+ import { assertArgument } from '@dxos/invariant';
9
12
 
10
13
  import { consoleLogger, noopLogger } from './logger';
11
- import { AiService, QueueService, ServiceContainer } from '../services';
12
- import type { EventLogger } from '../services/event-logger';
14
+ import {
15
+ AiService,
16
+ ConfiguredCredentialsService,
17
+ type CredentialsService,
18
+ DatabaseService,
19
+ type EventLogger,
20
+ QueueService,
21
+ ServiceContainer,
22
+ type ServiceCredential,
23
+ ToolResolverService,
24
+ type TracingService,
25
+ } from '../services';
26
+
27
+ // TODO(burdon): Factor out.
28
+ export type OneOf<T> = {
29
+ [K in keyof T]: { [P in K]: T[P] } & { [P in Exclude<keyof T, K>]?: never };
30
+ }[keyof T];
31
+
32
+ export type AiServiceProvider = 'dev' | 'edge' | 'ollama' | 'lmstudio';
13
33
 
14
34
  export type TestServiceOptions = {
15
- ai?: AiServiceClient;
16
- queueFactory?: QueueFactory;
17
- enableLogging?: boolean;
18
- logger?: Context.Tag.Service<EventLogger>;
35
+ /**
36
+ * AI service configuration.
37
+ */
38
+ ai?: OneOf<{
39
+ /**
40
+ * Custom AI service client.
41
+ */
42
+ client?: AiServiceClient;
43
+
44
+ /**
45
+ * Edge AI service at specified endpoint.
46
+ */
47
+ endpoint?: AiServiceEdgeClientOptions['endpoint'];
48
+
49
+ /**
50
+ * Predefined AI service configuration.
51
+ */
52
+ // TODO(burdon): 'dev' and 'edge' are redundant with providing an endpoint.
53
+ provider?: AiServiceProvider;
54
+ }>;
55
+
56
+ /**
57
+ * Credentials service configuration.
58
+ */
59
+ credentials?: OneOf<{
60
+ /**
61
+ * Predefined credentials list.
62
+ */
63
+ services?: ServiceCredential[];
64
+
65
+ /**
66
+ * Custom credentials service.
67
+ */
68
+ service?: Context.Tag.Service<CredentialsService>;
69
+ }>;
70
+
71
+ /**
72
+ * Database configuration.
73
+ */
74
+ db?: EchoDatabase;
75
+
76
+ /**
77
+ * Gets database and queue services from the space.
78
+ * Exclusive with: `db`, `queues`
79
+ */
80
+ space?: Space;
81
+
82
+ /**
83
+ * Logging configuration.
84
+ */
85
+ logging?: {
86
+ enabled?: boolean;
87
+ logger?: Context.Tag.Service<EventLogger>;
88
+ };
89
+
90
+ /**
91
+ * Queue service configuration.
92
+ */
93
+ queues?: QueueFactory;
94
+
95
+ tracing?: {
96
+ service?: Context.Tag.Service<TracingService>;
97
+ };
98
+
99
+ toolResolver?: Context.Tag.Service<ToolResolverService>;
19
100
  };
20
101
 
21
102
  export const createTestServices = ({
22
103
  ai,
23
- queueFactory,
24
- enableLogging = false,
25
- logger = enableLogging ? consoleLogger : noopLogger,
104
+ credentials,
105
+ db,
106
+ logging,
107
+ queues,
108
+ space,
109
+ tracing,
110
+ toolResolver,
26
111
  }: TestServiceOptions = {}): ServiceContainer => {
112
+ assertArgument(!(!!space && (!!db || !!queues)), 'space can be provided only if db and queues are not');
113
+
27
114
  return new ServiceContainer().setServices({
28
- ai: ai != null ? AiService.make(ai) : undefined,
29
- eventLogger: logger,
30
- queues: queueFactory != null ? QueueService.make(queueFactory, undefined) : undefined,
115
+ ai: createAiService(ai),
116
+ credentials: createCredentialsService(credentials),
117
+ database: space || db ? DatabaseService.make(space?.db || db!) : undefined,
118
+ eventLogger: logging?.logger ?? logging?.enabled ? consoleLogger : noopLogger,
119
+ queues: space || queues ? QueueService.make(space?.queues || queues!, undefined) : undefined,
120
+ tracing: tracing?.service,
121
+ toolResolver: toolResolver ?? ToolResolverService.make(new ToolRegistry([])),
31
122
  });
32
123
  };
124
+
125
+ // TODO(burdon): Enable model configuration.
126
+ const createAiService = (ai: TestServiceOptions['ai']): Context.Tag.Service<AiService> | undefined => {
127
+ if (ai?.client != null) {
128
+ return AiService.make(ai.client);
129
+ }
130
+
131
+ if (ai?.endpoint != null) {
132
+ return AiService.make(new EdgeAiServiceClient({ endpoint: ai.endpoint }));
133
+ }
134
+
135
+ switch (ai?.provider) {
136
+ case 'dev':
137
+ return AiService.make(
138
+ new EdgeAiServiceClient({
139
+ endpoint: AI_SERVICE_ENDPOINT.LOCAL,
140
+ defaultGenerationOptions: {
141
+ model: '@anthropic/claude-3-5-sonnet-20241022',
142
+ },
143
+ }),
144
+ );
145
+
146
+ case 'edge':
147
+ return AiService.make(
148
+ new EdgeAiServiceClient({
149
+ endpoint: AI_SERVICE_ENDPOINT.REMOTE,
150
+ defaultGenerationOptions: {
151
+ model: '@anthropic/claude-3-5-sonnet-20241022',
152
+ },
153
+ }),
154
+ );
155
+
156
+ case 'ollama':
157
+ return AiService.make(createTestAiServiceClient());
158
+
159
+ case 'lmstudio':
160
+ throw new Error('LMStudio is not supported');
161
+ }
162
+ };
163
+
164
+ const createCredentialsService = (
165
+ credentials: TestServiceOptions['credentials'] | undefined,
166
+ ): Context.Tag.Service<CredentialsService> | undefined => {
167
+ if (credentials?.services) {
168
+ return new ConfiguredCredentialsService(credentials.services);
169
+ }
170
+
171
+ if (credentials?.service) {
172
+ return credentials.service;
173
+ }
174
+ };
@@ -2,14 +2,14 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Type } from '@dxos/echo';
5
+ import { type Resource } from 'i18next';
6
6
 
7
7
  import { ScriptType } from './schema';
8
8
 
9
- export default [
9
+ export const translations = [
10
10
  {
11
11
  'en-US': {
12
- [Type.getTypename(ScriptType)]: {
12
+ [ScriptType.typename]: {
13
13
  'typename label': 'Script',
14
14
  'typename label_zero': 'Scripts',
15
15
  'typename label_one': 'Script',
@@ -17,4 +17,4 @@ export default [
17
17
  },
18
18
  },
19
19
  },
20
- ];
20
+ ] as const satisfies Resource[];