@dxos/functions 0.8.4-main.3f58842 → 0.8.4-main.5acf9ea
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/{chunk-3NGCSUEW.mjs → chunk-6PTFLPCO.mjs} +194 -60
- package/dist/lib/browser/chunk-6PTFLPCO.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +13 -15
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +2 -34
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/{chunk-FJ2MU7TL.mjs → chunk-NYJ2TSXO.mjs} +194 -60
- package/dist/lib/node-esm/chunk-NYJ2TSXO.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +13 -15
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +2 -34
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/services/credentials.d.ts +3 -2
- package/dist/types/src/services/credentials.d.ts.map +1 -1
- package/dist/types/src/services/database.d.ts +2 -1
- package/dist/types/src/services/database.d.ts.map +1 -1
- package/dist/types/src/services/event-logger.d.ts +65 -30
- package/dist/types/src/services/event-logger.d.ts.map +1 -1
- package/dist/types/src/services/index.d.ts +2 -1
- package/dist/types/src/services/index.d.ts.map +1 -1
- package/dist/types/src/services/local-function-execution.d.ts +11 -0
- package/dist/types/src/services/local-function-execution.d.ts.map +1 -0
- package/dist/types/src/services/queues.d.ts +3 -2
- package/dist/types/src/services/queues.d.ts.map +1 -1
- package/dist/types/src/services/remote-function-execution-service.d.ts +15 -0
- package/dist/types/src/services/remote-function-execution-service.d.ts.map +1 -0
- package/dist/types/src/services/service-container.d.ts +4 -4
- package/dist/types/src/services/service-container.d.ts.map +1 -1
- package/dist/types/src/services/service-registry.d.ts +1 -1
- package/dist/types/src/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/services/tracing.d.ts +3 -2
- package/dist/types/src/services/tracing.d.ts.map +1 -1
- package/dist/types/src/testing/logger.d.ts +3 -3
- package/dist/types/src/testing/logger.d.ts.map +1 -1
- package/dist/types/src/testing/services.d.ts +6 -17
- package/dist/types/src/testing/services.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +32 -27
- package/src/services/credentials.ts +5 -2
- package/src/services/database.ts +5 -1
- package/src/services/event-logger.ts +67 -36
- package/src/services/index.ts +2 -1
- package/src/services/local-function-execution.ts +70 -0
- package/src/services/queues.ts +5 -2
- package/src/services/{function-call-service.ts → remote-function-execution-service.ts} +7 -5
- package/src/services/service-container.ts +7 -7
- package/src/services/service-registry.ts +4 -1
- package/src/services/tracing.ts +4 -2
- package/src/testing/logger.ts +3 -3
- package/src/testing/services.ts +8 -62
- package/dist/lib/browser/chunk-3NGCSUEW.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-FJ2MU7TL.mjs.map +0 -7
- package/dist/types/src/services/function-call-service.d.ts +0 -16
- package/dist/types/src/services/function-call-service.d.ts.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/functions",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.5acf9ea",
|
|
4
4
|
"description": "Functions API and runtime.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -12,22 +12,26 @@
|
|
|
12
12
|
"./bundler": {
|
|
13
13
|
"types": "./dist/types/src/bundler/index.d.ts",
|
|
14
14
|
"browser": "./dist/lib/browser/bundler/index.mjs",
|
|
15
|
-
"node": "./dist/lib/node-esm/bundler/index.mjs"
|
|
15
|
+
"node": "./dist/lib/node-esm/bundler/index.mjs",
|
|
16
|
+
"source": "./src/bundler/index.ts"
|
|
16
17
|
},
|
|
17
18
|
"./edge": {
|
|
18
19
|
"types": "./dist/types/src/edge/index.d.ts",
|
|
19
20
|
"browser": "./dist/lib/browser/edge/index.mjs",
|
|
20
|
-
"node": "./dist/lib/node-esm/edge/index.mjs"
|
|
21
|
+
"node": "./dist/lib/node-esm/edge/index.mjs",
|
|
22
|
+
"source": "./src/edge/index.ts"
|
|
21
23
|
},
|
|
22
24
|
".": {
|
|
23
25
|
"types": "./dist/types/src/index.d.ts",
|
|
24
26
|
"browser": "./dist/lib/browser/index.mjs",
|
|
25
|
-
"node": "./dist/lib/node-esm/index.mjs"
|
|
27
|
+
"node": "./dist/lib/node-esm/index.mjs",
|
|
28
|
+
"source": "./src/index.ts"
|
|
26
29
|
},
|
|
27
30
|
"./testing": {
|
|
28
31
|
"types": "./dist/types/src/testing/index.d.ts",
|
|
29
32
|
"browser": "./dist/lib/browser/testing/index.mjs",
|
|
30
|
-
"node": "./dist/lib/node-esm/testing/index.mjs"
|
|
33
|
+
"node": "./dist/lib/node-esm/testing/index.mjs",
|
|
34
|
+
"source": "./src/testing/index.ts"
|
|
31
35
|
}
|
|
32
36
|
},
|
|
33
37
|
"types": "dist/types/src/index.d.ts",
|
|
@@ -58,32 +62,33 @@
|
|
|
58
62
|
"i18next": "^24.2.1",
|
|
59
63
|
"iso-did": "^1.6.0",
|
|
60
64
|
"ws": "^8.14.2",
|
|
61
|
-
"@dxos/ai": "0.8.4-main.
|
|
62
|
-
"@dxos/async": "0.8.4-main.
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/
|
|
65
|
-
"@dxos/
|
|
66
|
-
"@dxos/
|
|
67
|
-
"@dxos/
|
|
68
|
-
"@dxos/echo": "0.8.4-main.
|
|
69
|
-
"@dxos/echo-protocol": "0.8.4-main.
|
|
70
|
-
"@dxos/echo-
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/keys": "0.8.4-main.
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/live-object": "0.8.4-main.
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/
|
|
80
|
-
"@dxos/
|
|
81
|
-
"@dxos/schema": "0.8.4-main.
|
|
65
|
+
"@dxos/ai": "0.8.4-main.5acf9ea",
|
|
66
|
+
"@dxos/async": "0.8.4-main.5acf9ea",
|
|
67
|
+
"@dxos/crypto": "0.8.4-main.5acf9ea",
|
|
68
|
+
"@dxos/client": "0.8.4-main.5acf9ea",
|
|
69
|
+
"@dxos/echo": "0.8.4-main.5acf9ea",
|
|
70
|
+
"@dxos/context": "0.8.4-main.5acf9ea",
|
|
71
|
+
"@dxos/debug": "0.8.4-main.5acf9ea",
|
|
72
|
+
"@dxos/echo-db": "0.8.4-main.5acf9ea",
|
|
73
|
+
"@dxos/echo-protocol": "0.8.4-main.5acf9ea",
|
|
74
|
+
"@dxos/echo-pipeline": "0.8.4-main.5acf9ea",
|
|
75
|
+
"@dxos/echo-schema": "0.8.4-main.5acf9ea",
|
|
76
|
+
"@dxos/edge-client": "0.8.4-main.5acf9ea",
|
|
77
|
+
"@dxos/effect": "0.8.4-main.5acf9ea",
|
|
78
|
+
"@dxos/errors": "0.8.4-main.5acf9ea",
|
|
79
|
+
"@dxos/keys": "0.8.4-main.5acf9ea",
|
|
80
|
+
"@dxos/invariant": "0.8.4-main.5acf9ea",
|
|
81
|
+
"@dxos/live-object": "0.8.4-main.5acf9ea",
|
|
82
|
+
"@dxos/log": "0.8.4-main.5acf9ea",
|
|
83
|
+
"@dxos/node-std": "0.8.4-main.5acf9ea",
|
|
84
|
+
"@dxos/protocols": "0.8.4-main.5acf9ea",
|
|
85
|
+
"@dxos/schema": "0.8.4-main.5acf9ea",
|
|
86
|
+
"@dxos/util": "0.8.4-main.5acf9ea"
|
|
82
87
|
},
|
|
83
88
|
"devDependencies": {
|
|
84
89
|
"@types/express": "^4.17.17",
|
|
85
90
|
"@types/ws": "^7.4.0",
|
|
86
|
-
"@dxos/agent": "0.8.4-main.
|
|
91
|
+
"@dxos/agent": "0.8.4-main.5acf9ea"
|
|
87
92
|
},
|
|
88
93
|
"publishConfig": {
|
|
89
94
|
"access": "public"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Context, Effect } from 'effect';
|
|
5
|
+
import { Context, Effect, Layer } from 'effect';
|
|
6
6
|
|
|
7
7
|
type CredentialQuery = {
|
|
8
8
|
service?: string;
|
|
@@ -17,7 +17,7 @@ export type ServiceCredential = {
|
|
|
17
17
|
apiKey?: string;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
export class CredentialsService extends Context.Tag('CredentialsService')<
|
|
20
|
+
export class CredentialsService extends Context.Tag('@dxos/functions/CredentialsService')<
|
|
21
21
|
CredentialsService,
|
|
22
22
|
{
|
|
23
23
|
/**
|
|
@@ -32,6 +32,9 @@ export class CredentialsService extends Context.Tag('CredentialsService')<
|
|
|
32
32
|
getCredential: (query: CredentialQuery) => Promise<ServiceCredential>;
|
|
33
33
|
}
|
|
34
34
|
>() {
|
|
35
|
+
static configuredLayer = (credentials: ServiceCredential[]) =>
|
|
36
|
+
Layer.succeed(CredentialsService, new ConfiguredCredentialsService(credentials));
|
|
37
|
+
|
|
35
38
|
static getCredential = (query: CredentialQuery): Effect.Effect<ServiceCredential, never, CredentialsService> =>
|
|
36
39
|
Effect.gen(function* () {
|
|
37
40
|
const credentials = yield* CredentialsService;
|
package/src/services/database.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { Filter, Live, Obj, Query, Ref, Relation } from '@dxos/echo';
|
|
|
8
8
|
import type { EchoDatabase, OneShotQueryResult, QueryResult } from '@dxos/echo-db';
|
|
9
9
|
import type { DXN } from '@dxos/keys';
|
|
10
10
|
|
|
11
|
-
export class DatabaseService extends Context.Tag('DatabaseService')<
|
|
11
|
+
export class DatabaseService extends Context.Tag('@dxos/functions/DatabaseService')<
|
|
12
12
|
DatabaseService,
|
|
13
13
|
{
|
|
14
14
|
readonly db: EchoDatabase;
|
|
@@ -28,6 +28,10 @@ export class DatabaseService extends Context.Tag('DatabaseService')<
|
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
+
static makeLayer = (db: EchoDatabase): Layer.Layer<DatabaseService> => {
|
|
32
|
+
return Layer.succeed(DatabaseService, DatabaseService.make(db));
|
|
33
|
+
};
|
|
34
|
+
|
|
31
35
|
static resolve: (dxn: DXN) => Effect.Effect<Obj.Any | Relation.Any, Error, DatabaseService> = Effect.fn(
|
|
32
36
|
function* (dxn) {
|
|
33
37
|
const { db } = yield* DatabaseService;
|
|
@@ -2,53 +2,81 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Effect, Context } from 'effect';
|
|
5
|
+
import { Effect, Context, Schema, Layer } from 'effect';
|
|
6
6
|
|
|
7
|
+
import { Obj, Type } from '@dxos/echo';
|
|
7
8
|
import { invariant } from '@dxos/invariant';
|
|
8
9
|
import { log, LogLevel } from '@dxos/log';
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
11
|
+
import { TracingService } from './tracing';
|
|
12
|
+
|
|
13
|
+
export const ComputeEventPayload = Schema.Union(
|
|
14
|
+
Schema.Struct({
|
|
15
|
+
type: Schema.Literal('begin-compute'),
|
|
16
|
+
nodeId: Schema.String,
|
|
17
|
+
inputs: Schema.Record({ key: Schema.String, value: Schema.Any }),
|
|
18
|
+
}),
|
|
19
|
+
Schema.Struct({
|
|
20
|
+
type: Schema.Literal('end-compute'),
|
|
21
|
+
nodeId: Schema.String,
|
|
22
|
+
outputs: Schema.Record({ key: Schema.String, value: Schema.Any }),
|
|
23
|
+
}),
|
|
24
|
+
Schema.Struct({
|
|
25
|
+
type: Schema.Literal('compute-input'),
|
|
26
|
+
nodeId: Schema.String,
|
|
27
|
+
property: Schema.String,
|
|
28
|
+
value: Schema.Any,
|
|
29
|
+
}),
|
|
30
|
+
Schema.Struct({
|
|
31
|
+
type: Schema.Literal('compute-output'),
|
|
32
|
+
nodeId: Schema.String,
|
|
33
|
+
property: Schema.String,
|
|
34
|
+
value: Schema.Any,
|
|
35
|
+
}),
|
|
36
|
+
Schema.Struct({
|
|
37
|
+
type: Schema.Literal('custom'),
|
|
38
|
+
nodeId: Schema.String,
|
|
39
|
+
event: Schema.Any,
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
export type ComputeEventPayload = Schema.Schema.Type<typeof ComputeEventPayload>;
|
|
38
43
|
|
|
39
|
-
export
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
export const ComputeEvent = Schema.Struct({
|
|
45
|
+
payload: ComputeEventPayload,
|
|
46
|
+
}).pipe(Type.Obj({ typename: 'dxos.org/type/ComputeEvent', version: '0.1.0' }));
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Logs event for the compute workflows.
|
|
50
|
+
*/
|
|
51
|
+
export class ComputeEventLogger extends Context.Tag('@dxos/functions/ComputeEventLogger')<
|
|
52
|
+
ComputeEventLogger,
|
|
53
|
+
{ readonly log: (event: ComputeEventPayload) => void; readonly nodeId: string | undefined }
|
|
42
54
|
>() {
|
|
43
|
-
static noop: Context.Tag.Service<
|
|
55
|
+
static noop: Context.Tag.Service<ComputeEventLogger> = {
|
|
44
56
|
log: () => {},
|
|
45
57
|
nodeId: undefined,
|
|
46
58
|
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Implements ComputeEventLogger using TracingService.
|
|
62
|
+
*/
|
|
63
|
+
static layerFromTracing = Layer.effect(
|
|
64
|
+
ComputeEventLogger,
|
|
65
|
+
Effect.gen(function* () {
|
|
66
|
+
const tracing = yield* TracingService;
|
|
67
|
+
return {
|
|
68
|
+
log: (event: ComputeEventPayload) => {
|
|
69
|
+
tracing.write(Obj.make(ComputeEvent, { payload: event }));
|
|
70
|
+
},
|
|
71
|
+
nodeId: undefined,
|
|
72
|
+
};
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
47
75
|
}
|
|
48
76
|
|
|
49
77
|
export const logCustomEvent = (data: any) =>
|
|
50
78
|
Effect.gen(function* () {
|
|
51
|
-
const logger = yield*
|
|
79
|
+
const logger = yield* ComputeEventLogger;
|
|
52
80
|
if (!logger.nodeId) {
|
|
53
81
|
throw new Error('logCustomEvent must be called within a node compute function');
|
|
54
82
|
}
|
|
@@ -67,7 +95,10 @@ export const createDefectLogger = <A, E, R>(): ((self: Effect.Effect<A, E, R>) =
|
|
|
67
95
|
}),
|
|
68
96
|
);
|
|
69
97
|
|
|
70
|
-
export const createEventLogger = (
|
|
98
|
+
export const createEventLogger = (
|
|
99
|
+
level: LogLevel,
|
|
100
|
+
message: string = 'event',
|
|
101
|
+
): Context.Tag.Service<ComputeEventLogger> => {
|
|
71
102
|
const logFunction = (
|
|
72
103
|
{
|
|
73
104
|
[LogLevel.WARN]: log.warn,
|
|
@@ -79,7 +110,7 @@ export const createEventLogger = (level: LogLevel, message: string = 'event'): C
|
|
|
79
110
|
)[level];
|
|
80
111
|
invariant(logFunction);
|
|
81
112
|
return {
|
|
82
|
-
log: (event:
|
|
113
|
+
log: (event: ComputeEventPayload) => {
|
|
83
114
|
logFunction(message, event);
|
|
84
115
|
},
|
|
85
116
|
nodeId: undefined,
|
package/src/services/index.ts
CHANGED
|
@@ -8,4 +8,5 @@ export * from './service-container';
|
|
|
8
8
|
export * from './credentials';
|
|
9
9
|
export * from './tracing';
|
|
10
10
|
export * from './event-logger';
|
|
11
|
-
export * from './function-
|
|
11
|
+
export * from './remote-function-execution-service';
|
|
12
|
+
export * from './local-function-execution';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Context, Effect, Layer, Schema } from 'effect';
|
|
6
|
+
|
|
7
|
+
import { todo } from '@dxos/debug';
|
|
8
|
+
|
|
9
|
+
import type { FunctionContext, FunctionDefinition } from '../handler';
|
|
10
|
+
import type { Services } from './service-container';
|
|
11
|
+
import { FunctionError } from '../errors';
|
|
12
|
+
|
|
13
|
+
export class LocalFunctionExecutionService extends Context.Tag('@dxos/functions/LocalFunctionExecutionService')<
|
|
14
|
+
LocalFunctionExecutionService,
|
|
15
|
+
{
|
|
16
|
+
// TODO(dmaretskyi): This should take function id instead of the definition object.
|
|
17
|
+
// TODO(dmaretskyi): Services should be satisfied from environment rather then bubbled up.
|
|
18
|
+
invokeFunction(fnDef: FunctionDefinition<any, any>, input: unknown): Effect.Effect<unknown, never, Services>;
|
|
19
|
+
}
|
|
20
|
+
>() {
|
|
21
|
+
static layer = Layer.succeed(LocalFunctionExecutionService, {
|
|
22
|
+
invokeFunction: (fnDef, input) => invokeFunction(fnDef, input),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const invokeFunction = (fnDef: FunctionDefinition<any, any>, input: any): Effect.Effect<unknown, never, Services> =>
|
|
27
|
+
Effect.gen(function* () {
|
|
28
|
+
// Assert input matches schema
|
|
29
|
+
const assertInput = fnDef.inputSchema.pipe(Schema.asserts);
|
|
30
|
+
(assertInput as any)(input);
|
|
31
|
+
|
|
32
|
+
const context: FunctionContext = {
|
|
33
|
+
getService: () => todo(),
|
|
34
|
+
getSpace: async (_spaceId: any) => {
|
|
35
|
+
throw new Error('Not available. Use the database service instead.');
|
|
36
|
+
},
|
|
37
|
+
space: undefined,
|
|
38
|
+
get ai(): never {
|
|
39
|
+
throw new Error('Not available. Use the ai service instead.');
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// TODO(dmaretskyi): This should be delegated to a function invoker service.
|
|
44
|
+
const data = yield* Effect.gen(function* () {
|
|
45
|
+
const result = fnDef.handler({ context, data: input });
|
|
46
|
+
if (Effect.isEffect(result)) {
|
|
47
|
+
return yield* (result as Effect.Effect<unknown, unknown, Services>).pipe(Effect.orDie);
|
|
48
|
+
} else if (
|
|
49
|
+
typeof result === 'object' &&
|
|
50
|
+
result !== null &&
|
|
51
|
+
'then' in result &&
|
|
52
|
+
typeof result.then === 'function'
|
|
53
|
+
) {
|
|
54
|
+
return yield* Effect.promise(() => result);
|
|
55
|
+
} else {
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
}).pipe(
|
|
59
|
+
Effect.orDie,
|
|
60
|
+
Effect.catchAllDefect((defect) =>
|
|
61
|
+
Effect.die(new FunctionError('Error running function', { context: { name: fnDef.name }, cause: defect })),
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Assert output matches schema
|
|
66
|
+
const assertOutput = fnDef.outputSchema?.pipe(Schema.asserts);
|
|
67
|
+
(assertOutput as any)(data);
|
|
68
|
+
|
|
69
|
+
return data;
|
|
70
|
+
}).pipe(Effect.withSpan('invokeFunction', { attributes: { name: fnDef.name } }));
|
package/src/services/queues.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { Queue, QueueAPI, QueueFactory } from '@dxos/echo-db';
|
|
|
9
9
|
/**
|
|
10
10
|
* Gives access to all queues.
|
|
11
11
|
*/
|
|
12
|
-
export class QueueService extends Context.Tag('QueueService')<
|
|
12
|
+
export class QueueService extends Context.Tag('@dxos/functions/QueueService')<
|
|
13
13
|
QueueService,
|
|
14
14
|
{
|
|
15
15
|
/**
|
|
@@ -42,12 +42,15 @@ export class QueueService extends Context.Tag('QueueService')<
|
|
|
42
42
|
contextQueue,
|
|
43
43
|
};
|
|
44
44
|
};
|
|
45
|
+
|
|
46
|
+
static makeLayer = (queues: QueueFactory, contextQueue?: Queue): Layer.Layer<QueueService> =>
|
|
47
|
+
Layer.succeed(QueueService, QueueService.make(queues, contextQueue));
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
/**
|
|
48
51
|
* Gives access to a specific queue passed as a context.
|
|
49
52
|
*/
|
|
50
|
-
export class ContextQueueService extends Context.Tag('ContextQueueService')<
|
|
53
|
+
export class ContextQueueService extends Context.Tag('@dxos/functions/ContextQueueService')<
|
|
51
54
|
ContextQueueService,
|
|
52
55
|
{
|
|
53
56
|
readonly contextQueue: Queue;
|
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Context } from 'effect';
|
|
5
|
+
import { Context, Layer } from 'effect';
|
|
6
6
|
|
|
7
7
|
import type { SpaceId } from '@dxos/keys';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Allows calling into other functions.
|
|
11
11
|
*/
|
|
12
|
-
export class
|
|
13
|
-
|
|
12
|
+
export class RemoteFunctionExecutionService extends Context.Tag('@dxos/functions/RemoteFunctionExecutionService')<
|
|
13
|
+
RemoteFunctionExecutionService,
|
|
14
14
|
{
|
|
15
15
|
callFunction(deployedFunctionId: string, input: any, spaceId?: SpaceId): Promise<any>;
|
|
16
16
|
}
|
|
17
17
|
>() {
|
|
18
|
-
static fromClient(baseUrl: string, spaceId: SpaceId): Context.Tag.Service<
|
|
18
|
+
static fromClient(baseUrl: string, spaceId: SpaceId): Context.Tag.Service<RemoteFunctionExecutionService> {
|
|
19
19
|
return {
|
|
20
20
|
callFunction: async (deployedFunctionId: string, input: any) => {
|
|
21
21
|
const url = getInvocationUrl(deployedFunctionId, baseUrl, { spaceId });
|
|
@@ -32,13 +32,15 @@ export class FunctionCallService extends Context.Tag('FunctionCallService')<
|
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
static mock = () => {
|
|
35
|
+
static mock = (): Context.Tag.Service<RemoteFunctionExecutionService> => {
|
|
36
36
|
return {
|
|
37
37
|
callFunction: async (deployedFunctionId: string, input: any) => {
|
|
38
38
|
return input;
|
|
39
39
|
},
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
|
+
|
|
43
|
+
static mockLayer = Layer.succeed(RemoteFunctionExecutionService, RemoteFunctionExecutionService.mock());
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
// TODO(dmaretskyi): Reconcile with `getInvocationUrl` in `@dxos/functions/edge`.
|
|
@@ -9,9 +9,9 @@ import { entries } from '@dxos/util';
|
|
|
9
9
|
|
|
10
10
|
import { ConfiguredCredentialsService, CredentialsService } from './credentials';
|
|
11
11
|
import { DatabaseService } from './database';
|
|
12
|
-
import {
|
|
13
|
-
import { FunctionCallService } from './function-call-service';
|
|
12
|
+
import { ComputeEventLogger } from './event-logger';
|
|
14
13
|
import { QueueService } from './queues';
|
|
14
|
+
import { RemoteFunctionExecutionService } from './remote-function-execution-service';
|
|
15
15
|
import { TracingService } from './tracing';
|
|
16
16
|
|
|
17
17
|
// TODO(dmaretskyi): Refactor this module to only rely on tags and not the human-assigned names.
|
|
@@ -23,8 +23,8 @@ const SERVICES = {
|
|
|
23
23
|
ai: AiService,
|
|
24
24
|
credentials: CredentialsService,
|
|
25
25
|
database: DatabaseService,
|
|
26
|
-
eventLogger:
|
|
27
|
-
functionCallService:
|
|
26
|
+
eventLogger: ComputeEventLogger,
|
|
27
|
+
functionCallService: RemoteFunctionExecutionService,
|
|
28
28
|
queues: QueueService,
|
|
29
29
|
tracing: TracingService,
|
|
30
30
|
} as const satisfies Record<string, Context.TagClass<any, string, any>>;
|
|
@@ -102,10 +102,10 @@ export class ServiceContainer {
|
|
|
102
102
|
const queues =
|
|
103
103
|
this._services.queues != null ? Layer.succeed(QueueService, this._services.queues) : QueueService.notAvailable;
|
|
104
104
|
const tracing = Layer.succeed(TracingService, this._services.tracing ?? TracingService.noop);
|
|
105
|
-
const eventLogger = Layer.succeed(
|
|
105
|
+
const eventLogger = Layer.succeed(ComputeEventLogger, this._services.eventLogger ?? ComputeEventLogger.noop);
|
|
106
106
|
const functionCallService = Layer.succeed(
|
|
107
|
-
|
|
108
|
-
this._services.functionCallService ??
|
|
107
|
+
RemoteFunctionExecutionService,
|
|
108
|
+
this._services.functionCallService ?? RemoteFunctionExecutionService.mock(),
|
|
109
109
|
);
|
|
110
110
|
|
|
111
111
|
return Layer.mergeAll(ai, credentials, database, queues, tracing, eventLogger, functionCallService);
|
|
@@ -12,7 +12,10 @@ export namespace ServiceRegistry {
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export class ServiceRegistry extends Context.Tag('ServiceRegistry')<
|
|
15
|
+
export class ServiceRegistry extends Context.Tag('@dxos/functions/ServiceRegistry')<
|
|
16
|
+
ServiceRegistry,
|
|
17
|
+
ServiceRegistry.Service
|
|
18
|
+
>() {
|
|
16
19
|
/**
|
|
17
20
|
* Resolves the service from the registry.
|
|
18
21
|
* @param tag Service tag to resolve.
|
package/src/services/tracing.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Context, Effect } from 'effect';
|
|
5
|
+
import { Context, Effect, Layer } from 'effect';
|
|
6
6
|
|
|
7
7
|
import { AgentStatus } from '@dxos/ai';
|
|
8
8
|
import { Obj } from '@dxos/echo';
|
|
@@ -12,7 +12,7 @@ import type { AnyEchoObject } from '@dxos/echo-schema';
|
|
|
12
12
|
* Provides a way for compute primitives (functions, workflows, tools)
|
|
13
13
|
* to emit an execution trace as a series of structured ECHO objects.
|
|
14
14
|
*/
|
|
15
|
-
export class TracingService extends Context.Tag('TracingService')<
|
|
15
|
+
export class TracingService extends Context.Tag('@dxos/functions/TracingService')<
|
|
16
16
|
TracingService,
|
|
17
17
|
{
|
|
18
18
|
/**
|
|
@@ -24,6 +24,8 @@ export class TracingService extends Context.Tag('TracingService')<
|
|
|
24
24
|
>() {
|
|
25
25
|
static noop: Context.Tag.Service<TracingService> = { write: () => {} };
|
|
26
26
|
|
|
27
|
+
static layerNoop = Layer.succeed(TracingService, TracingService.noop);
|
|
28
|
+
|
|
27
29
|
static console: Context.Tag.Service<TracingService> = {
|
|
28
30
|
write: (event) => {
|
|
29
31
|
// eslint-disable-next-line no-console
|
package/src/testing/logger.ts
CHANGED
|
@@ -6,11 +6,11 @@ import { Effect, type Context } from 'effect';
|
|
|
6
6
|
|
|
7
7
|
import { LogLevel } from '@dxos/log';
|
|
8
8
|
|
|
9
|
-
import { type
|
|
9
|
+
import { type ComputeEventLogger, createEventLogger } from '../services';
|
|
10
10
|
|
|
11
|
-
export const noopLogger: Context.Tag.Service<
|
|
11
|
+
export const noopLogger: Context.Tag.Service<ComputeEventLogger> = {
|
|
12
12
|
log: () => Effect.succeed(undefined),
|
|
13
13
|
nodeId: undefined,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export const consoleLogger: Context.Tag.Service<
|
|
16
|
+
export const consoleLogger: Context.Tag.Service<ComputeEventLogger> = createEventLogger(LogLevel.INFO);
|
package/src/testing/services.ts
CHANGED
|
@@ -4,23 +4,21 @@
|
|
|
4
4
|
|
|
5
5
|
import { type Context } from 'effect';
|
|
6
6
|
|
|
7
|
-
import { AiService, type AiServiceClient, type AiServiceEdgeClientOptions, EdgeAiServiceClient } from '@dxos/ai';
|
|
8
|
-
import { AI_SERVICE_ENDPOINT, createTestAiServiceClient } from '@dxos/ai/testing';
|
|
9
7
|
import type { Space } from '@dxos/client/echo';
|
|
10
8
|
import type { EchoDatabase, QueueFactory } from '@dxos/echo-db';
|
|
11
9
|
import { assertArgument } from '@dxos/invariant';
|
|
12
10
|
|
|
13
|
-
import { consoleLogger, noopLogger } from './logger';
|
|
14
11
|
import {
|
|
15
12
|
ConfiguredCredentialsService,
|
|
16
13
|
type CredentialsService,
|
|
17
14
|
DatabaseService,
|
|
18
|
-
type
|
|
15
|
+
type ComputeEventLogger,
|
|
19
16
|
QueueService,
|
|
20
17
|
ServiceContainer,
|
|
21
18
|
type ServiceCredential,
|
|
22
19
|
type TracingService,
|
|
23
20
|
} from '../services';
|
|
21
|
+
import { consoleLogger, noopLogger } from './logger';
|
|
24
22
|
|
|
25
23
|
// TODO(burdon): Factor out.
|
|
26
24
|
export type OneOf<T> = {
|
|
@@ -33,23 +31,7 @@ export type TestServiceOptions = {
|
|
|
33
31
|
/**
|
|
34
32
|
* AI service configuration.
|
|
35
33
|
*/
|
|
36
|
-
ai?:
|
|
37
|
-
/**
|
|
38
|
-
* Custom AI service client.
|
|
39
|
-
*/
|
|
40
|
-
client?: AiServiceClient;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Edge AI service at specified endpoint.
|
|
44
|
-
*/
|
|
45
|
-
endpoint?: AiServiceEdgeClientOptions['endpoint'];
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Predefined AI service configuration.
|
|
49
|
-
*/
|
|
50
|
-
// TODO(burdon): 'dev' and 'edge' are redundant with providing an endpoint.
|
|
51
|
-
provider?: AiServiceProvider;
|
|
52
|
-
}>;
|
|
34
|
+
ai?: any;
|
|
53
35
|
|
|
54
36
|
/**
|
|
55
37
|
* Credentials service configuration.
|
|
@@ -82,7 +64,7 @@ export type TestServiceOptions = {
|
|
|
82
64
|
*/
|
|
83
65
|
logging?: {
|
|
84
66
|
enabled?: boolean;
|
|
85
|
-
logger?: Context.Tag.Service<
|
|
67
|
+
logger?: Context.Tag.Service<ComputeEventLogger>;
|
|
86
68
|
};
|
|
87
69
|
|
|
88
70
|
/**
|
|
@@ -95,6 +77,9 @@ export type TestServiceOptions = {
|
|
|
95
77
|
};
|
|
96
78
|
};
|
|
97
79
|
|
|
80
|
+
/**
|
|
81
|
+
* @deprecated
|
|
82
|
+
*/
|
|
98
83
|
export const createTestServices = ({
|
|
99
84
|
ai,
|
|
100
85
|
credentials,
|
|
@@ -107,7 +92,7 @@ export const createTestServices = ({
|
|
|
107
92
|
assertArgument(!(!!space && (!!db || !!queues)), 'space can be provided only if db and queues are not');
|
|
108
93
|
|
|
109
94
|
return new ServiceContainer().setServices({
|
|
110
|
-
ai: createAiService(ai),
|
|
95
|
+
// ai: createAiService(ai),
|
|
111
96
|
credentials: createCredentialsService(credentials),
|
|
112
97
|
database: space || db ? DatabaseService.make(space?.db || db!) : undefined,
|
|
113
98
|
eventLogger: (logging?.logger ?? logging?.enabled) ? consoleLogger : noopLogger,
|
|
@@ -116,45 +101,6 @@ export const createTestServices = ({
|
|
|
116
101
|
});
|
|
117
102
|
};
|
|
118
103
|
|
|
119
|
-
// TODO(burdon): Enable model configuration.
|
|
120
|
-
const createAiService = (ai: TestServiceOptions['ai']): Context.Tag.Service<AiService> | undefined => {
|
|
121
|
-
if (ai?.client != null) {
|
|
122
|
-
return AiService.make(ai.client);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (ai?.endpoint != null) {
|
|
126
|
-
return AiService.make(new EdgeAiServiceClient({ endpoint: ai.endpoint }));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
switch (ai?.provider) {
|
|
130
|
-
case 'dev':
|
|
131
|
-
return AiService.make(
|
|
132
|
-
new EdgeAiServiceClient({
|
|
133
|
-
endpoint: AI_SERVICE_ENDPOINT.LOCAL,
|
|
134
|
-
defaultGenerationOptions: {
|
|
135
|
-
model: '@anthropic/claude-3-5-sonnet-20241022',
|
|
136
|
-
},
|
|
137
|
-
}),
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
case 'edge':
|
|
141
|
-
return AiService.make(
|
|
142
|
-
new EdgeAiServiceClient({
|
|
143
|
-
endpoint: AI_SERVICE_ENDPOINT.REMOTE,
|
|
144
|
-
defaultGenerationOptions: {
|
|
145
|
-
model: '@anthropic/claude-3-5-sonnet-20241022',
|
|
146
|
-
},
|
|
147
|
-
}),
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
case 'ollama':
|
|
151
|
-
return AiService.make(createTestAiServiceClient());
|
|
152
|
-
|
|
153
|
-
case 'lmstudio':
|
|
154
|
-
throw new Error('LMStudio is not supported');
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
104
|
const createCredentialsService = (
|
|
159
105
|
credentials: TestServiceOptions['credentials'] | undefined,
|
|
160
106
|
): Context.Tag.Service<CredentialsService> | undefined => {
|