@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.
- package/dist/lib/browser/bundler/index.mjs +21 -10
- package/dist/lib/browser/bundler/index.mjs.map +3 -3
- package/dist/lib/browser/{chunk-WEFZUEL2.mjs → chunk-54U464M4.mjs} +79 -19
- package/dist/lib/browser/chunk-54U464M4.mjs.map +7 -0
- package/dist/lib/browser/edge/index.mjs +2 -2
- package/dist/lib/browser/index.mjs +20 -14
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +58 -7
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node-esm/bundler/index.mjs +21 -10
- package/dist/lib/node-esm/bundler/index.mjs.map +3 -3
- package/dist/lib/node-esm/{chunk-LIYPMWNQ.mjs → chunk-XDSX35BS.mjs} +79 -19
- package/dist/lib/node-esm/chunk-XDSX35BS.mjs.map +7 -0
- package/dist/lib/node-esm/edge/index.mjs +2 -2
- package/dist/lib/node-esm/index.mjs +20 -14
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +58 -7
- package/dist/lib/node-esm/testing/index.mjs.map +4 -4
- package/dist/types/src/bundler/bundler.d.ts +1 -2
- package/dist/types/src/bundler/bundler.d.ts.map +1 -1
- package/dist/types/src/executor/executor.d.ts.map +1 -1
- package/dist/types/src/handler.d.ts +3 -6
- package/dist/types/src/handler.d.ts.map +1 -1
- package/dist/types/src/schema.d.ts +3 -3
- package/dist/types/src/services/credentials.d.ts +1 -1
- package/dist/types/src/services/credentials.d.ts.map +1 -1
- package/dist/types/src/services/database.d.ts +5 -1
- package/dist/types/src/services/database.d.ts.map +1 -1
- package/dist/types/src/services/index.d.ts +1 -0
- package/dist/types/src/services/index.d.ts.map +1 -1
- package/dist/types/src/services/queues.d.ts +2 -2
- package/dist/types/src/services/queues.d.ts.map +1 -1
- package/dist/types/src/services/service-container.d.ts +3 -1
- package/dist/types/src/services/service-container.d.ts.map +1 -1
- package/dist/types/src/services/tool-resolver.d.ts +14 -0
- package/dist/types/src/services/tool-resolver.d.ts.map +1 -0
- package/dist/types/src/testing/services.d.ts +67 -9
- package/dist/types/src/testing/services.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +9 -9
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +29 -26
- package/src/bundler/bundler.test.ts +1 -1
- package/src/bundler/bundler.ts +26 -4
- package/src/executor/executor.ts +15 -8
- package/src/handler.ts +6 -6
- package/src/services/credentials.ts +1 -1
- package/src/services/database.ts +23 -1
- package/src/services/index.ts +1 -0
- package/src/services/queues.ts +9 -4
- package/src/services/service-container.ts +21 -3
- package/src/services/tool-resolver.ts +31 -0
- package/src/testing/services.ts +156 -14
- package/src/translations.ts +4 -4
- package/dist/lib/browser/chunk-WEFZUEL2.mjs.map +0 -7
- package/dist/lib/node/bundler/index.cjs +0 -260
- package/dist/lib/node/bundler/index.cjs.map +0 -7
- package/dist/lib/node/chunk-IJAE7FZK.cjs +0 -320
- package/dist/lib/node/chunk-IJAE7FZK.cjs.map +0 -7
- package/dist/lib/node/edge/index.cjs +0 -94
- package/dist/lib/node/edge/index.cjs.map +0 -7
- package/dist/lib/node/index.cjs +0 -522
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node/testing/index.cjs +0 -43
- package/dist/lib/node/testing/index.cjs.map +0 -7
- 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
|
+
"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.
|
|
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.
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/
|
|
65
|
-
"@dxos/echo-
|
|
66
|
-
"@dxos/echo-
|
|
67
|
-
"@dxos/echo-schema": "0.8.
|
|
68
|
-
"@dxos/edge-client": "0.8.
|
|
69
|
-
"@dxos/
|
|
70
|
-
"@dxos/keys": "0.8.
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/
|
|
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.
|
|
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
|
|
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({
|
package/src/bundler/bundler.ts
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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
|
-
|
|
267
|
-
|
|
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
|
};
|
package/src/executor/executor.ts
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
}
|
package/src/services/database.ts
CHANGED
|
@@ -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
|
}
|
package/src/services/index.ts
CHANGED
package/src/services/queues.ts
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
26
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
+
}
|
package/src/testing/services.ts
CHANGED
|
@@ -4,29 +4,171 @@
|
|
|
4
4
|
|
|
5
5
|
import { type Context } from 'effect';
|
|
6
6
|
|
|
7
|
-
import type
|
|
8
|
-
import
|
|
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 {
|
|
12
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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:
|
|
29
|
-
|
|
30
|
-
|
|
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
|
+
};
|
package/src/translations.ts
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { type Resource } from 'i18next';
|
|
6
6
|
|
|
7
7
|
import { ScriptType } from './schema';
|
|
8
8
|
|
|
9
|
-
export
|
|
9
|
+
export const translations = [
|
|
10
10
|
{
|
|
11
11
|
'en-US': {
|
|
12
|
-
[
|
|
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[];
|