@dxos/react-ui-canvas-compute 0.8.4-main.fd6878d → 0.8.4-staging.60fe92afc8

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 (126) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/browser/index.mjs +963 -1198
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/node-esm/index.mjs +963 -1198
  6. package/dist/lib/node-esm/index.mjs.map +4 -4
  7. package/dist/lib/node-esm/meta.json +1 -1
  8. package/dist/types/src/components/DiagnosticOverlay.d.ts.map +1 -1
  9. package/dist/types/src/compute-layout.d.ts.map +1 -1
  10. package/dist/types/src/compute.stories.d.ts +33 -5
  11. package/dist/types/src/compute.stories.d.ts.map +1 -1
  12. package/dist/types/src/graph/controller.d.ts +54 -53
  13. package/dist/types/src/graph/controller.d.ts.map +1 -1
  14. package/dist/types/src/graph/node-defs.d.ts.map +1 -1
  15. package/dist/types/src/hooks/useComputeGraphController.d.ts +1 -1
  16. package/dist/types/src/hooks/useComputeGraphController.d.ts.map +1 -1
  17. package/dist/types/src/hooks/useComputeNodeState.d.ts +4 -5
  18. package/dist/types/src/hooks/useComputeNodeState.d.ts.map +1 -1
  19. package/dist/types/src/hooks/useGraphMonitor.d.ts +2 -2
  20. package/dist/types/src/hooks/useGraphMonitor.d.ts.map +1 -1
  21. package/dist/types/src/json.test.d.ts +1 -1
  22. package/dist/types/src/json.test.d.ts.map +1 -1
  23. package/dist/types/src/shapes/Append.d.ts +2 -2
  24. package/dist/types/src/shapes/Append.d.ts.map +1 -1
  25. package/dist/types/src/shapes/Array.d.ts +2 -2
  26. package/dist/types/src/shapes/Array.d.ts.map +1 -1
  27. package/dist/types/src/shapes/Audio.d.ts +2 -2
  28. package/dist/types/src/shapes/Audio.d.ts.map +1 -1
  29. package/dist/types/src/shapes/Beacon.d.ts +2 -2
  30. package/dist/types/src/shapes/Beacon.d.ts.map +1 -1
  31. package/dist/types/src/shapes/Boolean.d.ts +8 -8
  32. package/dist/types/src/shapes/Boolean.d.ts.map +1 -1
  33. package/dist/types/src/shapes/Chat.d.ts +2 -2
  34. package/dist/types/src/shapes/Chat.d.ts.map +1 -1
  35. package/dist/types/src/shapes/Constant.d.ts +3 -3
  36. package/dist/types/src/shapes/Constant.d.ts.map +1 -1
  37. package/dist/types/src/shapes/Database.d.ts +2 -2
  38. package/dist/types/src/shapes/Database.d.ts.map +1 -1
  39. package/dist/types/src/shapes/{Queue.d.ts → Feed.d.ts} +10 -10
  40. package/dist/types/src/shapes/Feed.d.ts.map +1 -0
  41. package/dist/types/src/shapes/Function.d.ts +2 -2
  42. package/dist/types/src/shapes/Function.d.ts.map +1 -1
  43. package/dist/types/src/shapes/Gpt.d.ts +2 -2
  44. package/dist/types/src/shapes/Gpt.d.ts.map +1 -1
  45. package/dist/types/src/shapes/GptRealtime.d.ts +2 -2
  46. package/dist/types/src/shapes/GptRealtime.d.ts.map +1 -1
  47. package/dist/types/src/shapes/Json.d.ts +3 -3
  48. package/dist/types/src/shapes/Json.d.ts.map +1 -1
  49. package/dist/types/src/shapes/Logic.d.ts +3 -3
  50. package/dist/types/src/shapes/Logic.d.ts.map +1 -1
  51. package/dist/types/src/shapes/RNG.d.ts +3 -3
  52. package/dist/types/src/shapes/RNG.d.ts.map +1 -1
  53. package/dist/types/src/shapes/Scope.d.ts +2 -2
  54. package/dist/types/src/shapes/Scope.d.ts.map +1 -1
  55. package/dist/types/src/shapes/Surface.d.ts +2 -2
  56. package/dist/types/src/shapes/Surface.d.ts.map +1 -1
  57. package/dist/types/src/shapes/Switch.d.ts +2 -2
  58. package/dist/types/src/shapes/Switch.d.ts.map +1 -1
  59. package/dist/types/src/shapes/Table.d.ts +2 -2
  60. package/dist/types/src/shapes/Table.d.ts.map +1 -1
  61. package/dist/types/src/shapes/Template.d.ts +3 -3
  62. package/dist/types/src/shapes/Template.d.ts.map +1 -1
  63. package/dist/types/src/shapes/Text.d.ts +2 -2
  64. package/dist/types/src/shapes/Text.d.ts.map +1 -1
  65. package/dist/types/src/shapes/TextToImage.d.ts +2 -2
  66. package/dist/types/src/shapes/TextToImage.d.ts.map +1 -1
  67. package/dist/types/src/shapes/Thread.d.ts +2 -2
  68. package/dist/types/src/shapes/Thread.d.ts.map +1 -1
  69. package/dist/types/src/shapes/Trigger.d.ts +11 -61
  70. package/dist/types/src/shapes/Trigger.d.ts.map +1 -1
  71. package/dist/types/src/shapes/common/Box.d.ts +4 -4
  72. package/dist/types/src/shapes/common/Box.d.ts.map +1 -1
  73. package/dist/types/src/shapes/common/FunctionBody.d.ts +3 -3
  74. package/dist/types/src/shapes/common/FunctionBody.d.ts.map +1 -1
  75. package/dist/types/src/shapes/common/TypeSelect.d.ts +1 -1
  76. package/dist/types/src/shapes/common/TypeSelect.d.ts.map +1 -1
  77. package/dist/types/src/shapes/defs.d.ts +3 -2
  78. package/dist/types/src/shapes/defs.d.ts.map +1 -1
  79. package/dist/types/src/shapes/index.d.ts +2 -2
  80. package/dist/types/src/shapes/index.d.ts.map +1 -1
  81. package/dist/types/src/testing/circuits.d.ts +18 -24
  82. package/dist/types/src/testing/circuits.d.ts.map +1 -1
  83. package/dist/types/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +63 -57
  85. package/src/README.md +0 -3
  86. package/src/compute-layout.ts +1 -1
  87. package/src/compute.stories.tsx +100 -123
  88. package/src/graph/controller.ts +158 -79
  89. package/src/graph/node-defs.ts +31 -31
  90. package/src/hooks/useComputeGraphController.ts +1 -1
  91. package/src/hooks/useComputeNodeState.ts +8 -9
  92. package/src/hooks/useGraphMonitor.ts +11 -10
  93. package/src/json.test.ts +4 -4
  94. package/src/registry.ts +2 -2
  95. package/src/schema.test.ts +12 -12
  96. package/src/shapes/Append.tsx +1 -1
  97. package/src/shapes/Array.tsx +1 -1
  98. package/src/shapes/Audio.tsx +2 -3
  99. package/src/shapes/Beacon.tsx +1 -2
  100. package/src/shapes/Boolean.tsx +2 -2
  101. package/src/shapes/Chat.tsx +1 -2
  102. package/src/shapes/Constant.tsx +1 -2
  103. package/src/shapes/Database.tsx +1 -1
  104. package/src/shapes/{Queue.tsx → Feed.tsx} +27 -22
  105. package/src/shapes/Function.tsx +16 -13
  106. package/src/shapes/Gpt.tsx +7 -3
  107. package/src/shapes/GptRealtime.tsx +1 -1
  108. package/src/shapes/Json.tsx +10 -4
  109. package/src/shapes/Logic.tsx +1 -1
  110. package/src/shapes/RNG.tsx +6 -3
  111. package/src/shapes/Scope.tsx +3 -3
  112. package/src/shapes/Surface.tsx +13 -5
  113. package/src/shapes/Switch.tsx +1 -2
  114. package/src/shapes/Table.tsx +5 -4
  115. package/src/shapes/Template.tsx +2 -3
  116. package/src/shapes/Text.tsx +1 -2
  117. package/src/shapes/TextToImage.tsx +1 -1
  118. package/src/shapes/Thread.tsx +14 -11
  119. package/src/shapes/Trigger.tsx +51 -58
  120. package/src/shapes/common/Box.tsx +6 -9
  121. package/src/shapes/common/FunctionBody.tsx +4 -3
  122. package/src/shapes/common/TypeSelect.tsx +1 -1
  123. package/src/shapes/defs.ts +5 -4
  124. package/src/shapes/index.ts +2 -2
  125. package/src/testing/circuits.ts +9 -18
  126. package/dist/types/src/shapes/Queue.d.ts.map +0 -1
@@ -2,14 +2,26 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { type Context, Effect, Either, Exit, Scope } from 'effect';
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Either from 'effect/Either';
7
+ import * as Exit from 'effect/Exit';
8
+ import * as Layer from 'effect/Layer';
9
+ import * as Scope from 'effect/Scope';
6
10
 
11
+ import type { AiService } from '@dxos/ai';
7
12
  import { Event, synchronized } from '@dxos/async';
13
+ import { type Credential, type Operation, Trace } from '@dxos/compute';
8
14
  import {
15
+ ComputeBeginEvent,
16
+ ComputeCustomEvent,
17
+ ComputeEndEvent,
18
+ ComputeInputEvent,
19
+ ComputeNodeContext,
20
+ ComputeOutputEvent,
9
21
  type ComputeEdge,
10
22
  type ComputeGraphModel,
11
- type ComputeMeta,
12
23
  type ComputeNode,
24
+ type ComputeNodeMeta,
13
25
  type GptInput,
14
26
  type GptOutput,
15
27
  type GraphDiagnostic,
@@ -18,15 +30,14 @@ import {
18
30
  isNotExecuted,
19
31
  } from '@dxos/conductor';
20
32
  import { Resource } from '@dxos/context';
21
- import { type ComputeEventLogger, type ComputeEventPayload } from '@dxos/functions';
22
- import { type ServiceContainer } from '@dxos/functions';
33
+ import type { Database, Feed, Registry } from '@dxos/echo';
34
+ import { EffectEx } from '@dxos/effect';
23
35
  import { log } from '@dxos/log';
24
36
  import { type CanvasGraphModel } from '@dxos/react-ui-canvas-editor';
25
- import { type ContentBlock } from '@dxos/schema';
37
+ import { type ContentBlock } from '@dxos/types';
26
38
 
27
39
  import { createComputeGraph } from '../hooks';
28
40
  import { type ComputeShape } from '../shapes';
29
-
30
41
  import { resolveComputeNode } from './node-defs';
31
42
 
32
43
  // TODO(burdon): API package for conductor.
@@ -68,17 +79,46 @@ type ComputeOutputEvent = {
68
79
  value: RuntimeValue;
69
80
  };
70
81
 
82
+ /**
83
+ * Event emitted by the compute graph during execution.
84
+ */
85
+ export type ComputeEvent =
86
+ | { type: 'begin-compute'; nodeId: string; inputs: ReadonlyArray<string> }
87
+ | { type: 'end-compute'; nodeId: string; outputs: ReadonlyArray<string> }
88
+ | { type: 'compute-input'; nodeId: string; property: string; value: any }
89
+ | { type: 'compute-output'; nodeId: string; property: string; value: any }
90
+ | { type: 'custom'; nodeId: string; event: any };
91
+
92
+ // TODO(dmaretskyi): Re-use function servies definition.
93
+ export type ComputeServices =
94
+ | AiService.AiService
95
+ | Database.Service
96
+ | Feed.FeedService
97
+ | Credential.CredentialsService
98
+ | Operation.Service
99
+ | Registry.Service;
100
+
71
101
  /**
72
102
  * Nodes that will automatically trigger the execution of the graph on startup.
73
103
  */
74
104
  const AUTO_TRIGGER_NODES = ['chat', 'switch', 'constant'];
75
105
 
106
+ /**
107
+ * Minimal runtime interface required by the {@link ComputeGraphController}.
108
+ *
109
+ * Satisfied by both `effect/ManagedRuntime.ManagedRuntime` and ad-hoc adapters
110
+ * built on top of the app-framework `ProcessManagerRuntime`.
111
+ */
112
+ export interface ComputeGraphRuntime {
113
+ runPromiseExit<A, E>(effect: Effect.Effect<A, E, ComputeServices>): Promise<Exit.Exit<A, E>>;
114
+ }
115
+
76
116
  export const createComputeGraphController = (
77
117
  graph: CanvasGraphModel<ComputeShape>,
78
- serviceContainer: ServiceContainer,
118
+ computeRuntime: ComputeGraphRuntime,
79
119
  ) => {
80
120
  const computeGraph = createComputeGraph(graph);
81
- const controller = new ComputeGraphController(serviceContainer, computeGraph);
121
+ const controller = new ComputeGraphController(computeRuntime, computeGraph);
82
122
  return { controller, graph };
83
123
  };
84
124
 
@@ -110,10 +150,10 @@ export class ComputeGraphController extends Resource {
110
150
  /** Computed result. */
111
151
  public readonly output = new Event<ComputeOutputEvent>();
112
152
 
113
- public readonly events = new Event<ComputeEventPayload>();
153
+ public readonly events = new Event<ComputeEvent>();
114
154
 
115
155
  constructor(
116
- private readonly _serviceContainer: ServiceContainer,
156
+ private readonly _computeRuntime: ComputeGraphRuntime,
117
157
  /** Persistent compute graph. */
118
158
  private readonly _graph: ComputeGraphModel,
119
159
  ) {
@@ -154,7 +194,14 @@ export class ComputeGraphController extends Resource {
154
194
  /**
155
195
  * Inputs and outputs for all nodes.
156
196
  */
157
- get state() {
197
+ get state(): Record<
198
+ string,
199
+ {
200
+ node: ComputeNode;
201
+ input: Record<string, RuntimeValue>;
202
+ output: Record<string, RuntimeValue>;
203
+ }
204
+ > {
158
205
  const ids = [...new Set([...Object.keys(this._runtimeStateInputs), ...Object.keys(this._runtimeStateOutputs)])];
159
206
  return Object.fromEntries(
160
207
  ids.map((id) => [
@@ -201,7 +248,7 @@ export class ComputeGraphController extends Resource {
201
248
  });
202
249
  }
203
250
 
204
- async getMeta(node: ComputeNode): Promise<ComputeMeta> {
251
+ async getMeta(node: ComputeNode): Promise<ComputeNodeMeta> {
205
252
  const { meta } = await resolveComputeNode(node);
206
253
  return meta;
207
254
  }
@@ -221,37 +268,42 @@ export class ComputeGraphController extends Resource {
221
268
  executor.setOutputs(nodeId, Effect.succeed(ValueBag.make(outputs)));
222
269
  }
223
270
 
224
- const serviceLayer = this._serviceContainer.createLayer();
225
- await Effect.runPromise(
226
- Effect.gen(this, function* () {
227
- const scope = yield* Scope.make();
228
-
229
- // TODO(dmaretskyi): Code duplication.
230
- const executable = yield* Effect.promise(() => resolveComputeNode(this._graph.getNode(nodeId)));
231
- const computingOutputs = executable.exec != null;
232
- // TODO(dmaretskyi): Check if the node has a compute function and run computeOutputs if it does.
233
- const effect = (computingOutputs ? executor.computeOutputs(nodeId) : executor.computeInputs(nodeId)).pipe(
234
- Effect.withSpan('runGraph'),
235
- Scope.extend(scope),
236
-
237
- Effect.flatMap(computeValueBag),
238
- Effect.provide(serviceLayer),
239
- Effect.withSpan('test'),
240
- Effect.tap((values) => {
241
- for (const [key, value] of Object.entries(values)) {
242
- if (computingOutputs) {
243
- this._onOutputComputed(nodeId, key, value);
244
- } else {
245
- this._onInputComputed(nodeId, key, value);
271
+ EffectEx.unwrapExit(
272
+ await this._computeRuntime.runPromiseExit(
273
+ Effect.gen(this, function* () {
274
+ const scope = yield* Scope.make();
275
+
276
+ // TODO(dmaretskyi): Code duplication.
277
+ const executable = yield* Effect.promise(() => resolveComputeNode(this._graph.getNode(nodeId)));
278
+ const computingOutputs = executable.exec != null;
279
+ // TODO(dmaretskyi): Check if the node has a compute function and run computeOutputs if it does.
280
+ const effect = (computingOutputs ? executor.computeOutputs(nodeId) : executor.computeInputs(nodeId)).pipe(
281
+ Effect.withSpan('runGraph'),
282
+ Scope.extend(scope),
283
+ Effect.provide(
284
+ Layer.mergeAll(
285
+ Layer.succeed(Trace.TraceService, this._createTraceWriter()),
286
+ ComputeNodeContext.layerNoop,
287
+ ),
288
+ ),
289
+ Effect.flatMap(computeValueBag),
290
+ Effect.withSpan('test'),
291
+ Effect.tap((values) => {
292
+ for (const [key, value] of Object.entries(values)) {
293
+ if (computingOutputs) {
294
+ this._onOutputComputed(nodeId, key, value);
295
+ } else {
296
+ this._onInputComputed(nodeId, key, value);
297
+ }
246
298
  }
247
- }
248
- }),
249
- );
299
+ }),
300
+ );
250
301
 
251
- yield* effect;
302
+ yield* effect;
252
303
 
253
- yield* Scope.close(scope, Exit.void);
254
- }),
304
+ yield* Scope.close(scope, Exit.void);
305
+ }),
306
+ ),
255
307
  );
256
308
 
257
309
  this.update.emit();
@@ -279,59 +331,69 @@ export class ComputeGraphController extends Resource {
279
331
  : this._graph.nodes.filter((node) => node.type != null && AUTO_TRIGGER_NODES.includes(node.type));
280
332
  const allAffectedNodes = [...new Set(triggerNodes.flatMap((node) => executor.getAllDependantNodes(node.id)))];
281
333
 
282
- await Effect.runPromise(
283
- Effect.gen(this, function* () {
284
- const scope = yield* Scope.make();
285
-
286
- // TODO(burdon): Return map?
287
- const tasks: Effect.Effect<unknown, any, never>[] = [];
288
- for (const node of allAffectedNodes) {
289
- // TODO(dmaretskyi): Code duplication.
290
- const executable = yield* Effect.promise(() => resolveComputeNode(this._graph.getNode(node)));
291
- const computingOutputs = executable.exec != null;
292
-
293
- // TODO(dmaretskyi): Check if the node has a compute function and run computeOutputs if it does.
294
- const effect = (computingOutputs ? executor.computeOutputs(node) : executor.computeInputs(node)).pipe(
295
- Effect.withSpan('runGraph'),
296
- Scope.extend(scope),
297
- Effect.flatMap(computeValueBag),
298
- Effect.provide(this._serviceContainer.createLayer()),
299
- Effect.withSpan('test'),
300
- Effect.tap((values) => {
301
- for (const [key, value] of Object.entries(values)) {
302
- if (computingOutputs) {
303
- this._onOutputComputed(node, key, value);
304
- } else {
305
- this._onInputComputed(node, key, value);
334
+ EffectEx.unwrapExit(
335
+ await this._computeRuntime.runPromiseExit(
336
+ Effect.gen(this, function* () {
337
+ const scope = yield* Scope.make();
338
+
339
+ // TODO(burdon): Return map?
340
+ const tasks: Effect.Effect<unknown, any, ComputeServices>[] = [];
341
+ for (const node of allAffectedNodes) {
342
+ // TODO(dmaretskyi): Code duplication.
343
+ const executable = yield* Effect.promise(() => resolveComputeNode(this._graph.getNode(node)));
344
+ const computingOutputs = executable.exec != null;
345
+
346
+ // TODO(dmaretskyi): Check if the node has a compute function and run computeOutputs if it does.
347
+ const effect = (computingOutputs ? executor.computeOutputs(node) : executor.computeInputs(node)).pipe(
348
+ Effect.withSpan('runGraph'),
349
+ Scope.extend(scope),
350
+ Effect.flatMap(computeValueBag),
351
+ Effect.provide(
352
+ Layer.mergeAll(
353
+ Layer.succeed(Trace.TraceService, this._createTraceWriter()),
354
+ ComputeNodeContext.layerNoop,
355
+ ),
356
+ ),
357
+
358
+ Effect.withSpan('test'),
359
+ Effect.tap((values) => {
360
+ for (const [key, value] of Object.entries(values)) {
361
+ if (computingOutputs) {
362
+ this._onOutputComputed(node, key, value);
363
+ } else {
364
+ this._onInputComputed(node, key, value);
365
+ }
306
366
  }
307
- }
308
- }),
309
- );
367
+ }),
368
+ );
310
369
 
311
- tasks.push(effect);
312
- }
370
+ tasks.push(effect);
371
+ }
313
372
 
314
- //
315
- yield* Effect.all(tasks);
373
+ //
374
+ yield* Effect.all(tasks);
316
375
 
317
- //
318
- yield* Scope.close(scope, Exit.void);
319
- }),
376
+ //
377
+ yield* Scope.close(scope, Exit.void);
378
+ }),
379
+ ),
320
380
  );
321
381
 
322
382
  this.update.emit();
323
383
  }
324
384
 
325
- private _createLogger(): Context.Tag.Service<ComputeEventLogger> {
385
+ private _createTraceWriter(): Trace.TraceWriter {
326
386
  return {
327
- log: (event) => {
328
- this._handleEvent(event);
387
+ write: (eventType, payload) => {
388
+ const event = traceEventToComputeEvent(eventType.key, payload);
389
+ if (event) {
390
+ this._handleEvent(event);
391
+ }
329
392
  },
330
- nodeId: undefined, // Not in a context of a specific node.
331
393
  };
332
394
  }
333
395
 
334
- private _handleEvent(event: ComputeEventPayload): void {
396
+ private _handleEvent(event: ComputeEvent): void {
335
397
  log('handleEvent', { event });
336
398
  switch (event.type) {
337
399
  case 'compute-input': {
@@ -361,6 +423,23 @@ export class ComputeGraphController extends Resource {
361
423
  }
362
424
  }
363
425
 
426
+ const traceEventToComputeEvent = (key: string, payload: unknown): ComputeEvent | undefined => {
427
+ switch (key) {
428
+ case ComputeBeginEvent.key:
429
+ return { type: 'begin-compute', ...(payload as { nodeId: string; inputs: ReadonlyArray<string> }) };
430
+ case ComputeEndEvent.key:
431
+ return { type: 'end-compute', ...(payload as { nodeId: string; outputs: ReadonlyArray<string> }) };
432
+ case ComputeInputEvent.key:
433
+ return { type: 'compute-input', ...(payload as { nodeId: string; property: string; value: any }) };
434
+ case ComputeOutputEvent.key:
435
+ return { type: 'compute-output', ...(payload as { nodeId: string; property: string; value: any }) };
436
+ case ComputeCustomEvent.key:
437
+ return { type: 'custom', ...(payload as { nodeId: string; event: any }) };
438
+ default:
439
+ return undefined;
440
+ }
441
+ };
442
+
364
443
  /**
365
444
  * Waits for all effects in the bag to complete and returns the `RuntimeValue` for each property.
366
445
  */
@@ -12,7 +12,7 @@ import {
12
12
  registry,
13
13
  } from '@dxos/conductor';
14
14
  import { raise } from '@dxos/debug';
15
- import { ObjectId, toJsonSchema } from '@dxos/echo-schema';
15
+ import { JsonSchema, Obj } from '@dxos/echo';
16
16
  import { invariant } from '@dxos/invariant';
17
17
 
18
18
  import { type ComputeShape, type ConstantShape, type TemplateShape } from '../shapes';
@@ -39,45 +39,45 @@ const nodeFactory: Record<NodeType | 'trigger', (shape: ComputeShape) => Compute
39
39
  [NODE_OUTPUT]: () => createNode(NODE_OUTPUT),
40
40
 
41
41
  // Extensions.
42
- ['text-to-image' as const]: () => createNode('text-to-image'), // TODO(burdon): Rename ai-impage-tool
43
- ['and' as const]: () => createNode('and'),
44
- ['append' as const]: () => createNode('append'),
45
- ['audio' as const]: () => createNode('audio'),
46
- ['beacon' as const]: () => createNode('beacon'),
47
- ['chat' as const]: () => createNode('chat'),
48
- ['constant' as const]: (shape) =>
42
+ 'text-to-image': () => createNode('text-to-image'), // TODO(burdon): Rename ai-impage-tool
43
+ and: () => createNode('and'),
44
+ append: () => createNode('append'),
45
+ audio: () => createNode('audio'),
46
+ beacon: () => createNode('beacon'),
47
+ chat: () => createNode('chat'),
48
+ constant: (shape) =>
49
49
  createNode('constant', {
50
50
  value: (shape as ConstantShape).value,
51
51
  }),
52
- ['make-queue' as const]: () => createNode('make-queue'),
53
- ['database' as const]: () => createNode('database'),
54
- ['gpt' as const]: () => createNode('gpt'),
55
- ['gpt-realtime' as const]: () => createNode('gpt-realtime'),
56
- ['if' as const]: () => createNode('if'),
57
- ['if-else' as const]: () => createNode('if-else'),
58
- ['function' as const]: () => createNode('function'),
59
- ['json' as const]: () => createNode('json'),
60
- ['json-transform' as const]: () => createNode('json-transform'),
61
- ['not' as const]: () => createNode('not'),
62
- ['or' as const]: () => createNode('or'),
63
- ['queue' as const]: () => createNode('queue'),
64
- ['rng' as const]: () => createNode('rng'),
65
- ['reducer' as const]: () => createNode('reducer'),
66
- ['scope' as const]: () => createNode('scope'),
67
- ['surface' as const]: () => createNode('surface'),
68
- ['switch' as const]: () => createNode('switch'),
69
- ['template' as const]: (shape) => {
52
+ 'make-queue': () => createNode('make-queue'),
53
+ database: () => createNode('database'),
54
+ gpt: () => createNode('gpt'),
55
+ 'gpt-realtime': () => createNode('gpt-realtime'),
56
+ if: () => createNode('if'),
57
+ 'if-else': () => createNode('if-else'),
58
+ function: () => createNode('function'),
59
+ json: () => createNode('json'),
60
+ 'json-transform': () => createNode('json-transform'),
61
+ not: () => createNode('not'),
62
+ or: () => createNode('or'),
63
+ queue: () => createNode('queue'),
64
+ rng: () => createNode('rng'),
65
+ reducer: () => createNode('reducer'),
66
+ scope: () => createNode('scope'),
67
+ surface: () => createNode('surface'),
68
+ switch: () => createNode('switch'),
69
+ template: (shape) => {
70
70
  const node = createNode('template', { valueType: (shape as TemplateShape).valueType, value: shape.text });
71
- node.inputSchema = toJsonSchema(getTemplateInputSchema(node));
71
+ node.inputSchema = JsonSchema.toJsonSchema(getTemplateInputSchema(node));
72
72
  return node;
73
73
  },
74
- ['text' as const]: () => createNode('text'),
75
- ['thread' as const]: () => createNode('thread'),
76
- ['trigger' as const]: () => createNode(NODE_INPUT),
74
+ text: () => createNode('text'),
75
+ thread: () => createNode('thread'),
76
+ trigger: () => createNode(NODE_INPUT),
77
77
  };
78
78
 
79
79
  const createNode = (type: string, props?: Partial<ComputeNode>): ComputeNode => ({
80
- id: ObjectId.random(),
80
+ id: Obj.ID.random(),
81
81
  type,
82
82
  ...props,
83
83
  });
@@ -21,7 +21,7 @@ const combine = (...cbs: CleanupFn[]) => {
21
21
 
22
22
  export type UseComputeGraphControllerOptions = Pick<EditorRootProps<ComputeShape>, 'graph'> & {
23
23
  controller: ComputeGraphController | null;
24
- editorRef: RefObject<EditorController>;
24
+ editorRef: RefObject<EditorController | null>;
25
25
  };
26
26
 
27
27
  export const useComputeGraphController = ({ controller, graph, editorRef }: UseComputeGraphControllerOptions) => {
@@ -2,27 +2,25 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
  import { useCallback, useEffect, useState } from 'react';
7
7
 
8
- import type { ComputeMeta, ComputeNode } from '@dxos/conductor';
9
- import type { ComputeEventPayload } from '@dxos/functions';
8
+ import type { ComputeNode, ComputeNodeMeta } from '@dxos/conductor';
10
9
  import { invariant } from '@dxos/invariant';
11
10
 
12
- import { type RuntimeValue } from '../graph';
11
+ import { type ComputeEvent, type RuntimeValue } from '../graph';
13
12
  import { type ComputeShape } from '../shapes';
14
-
15
13
  import { useComputeContext } from './compute-context';
16
14
 
17
15
  export type ComputeNodeState = {
18
16
  node: ComputeNode;
19
- meta: ComputeMeta;
17
+ meta: ComputeNodeMeta;
20
18
  runtime: {
21
19
  inputs: Record<string, RuntimeValue>;
22
20
  outputs: Record<string, RuntimeValue>;
23
21
  setOutput: (property: string, value: any) => void;
24
22
  evalNode: () => void;
25
- subscribeToEventLog: (cb: (event: ComputeEventPayload) => void) => void;
23
+ subscribeToEventLog: (cb: (event: ComputeEvent) => void) => () => void;
26
24
  };
27
25
  };
28
26
 
@@ -33,7 +31,7 @@ export const useComputeNodeState = (shape: ComputeShape): ComputeNodeState => {
33
31
  const { controller } = useComputeContext();
34
32
  invariant(controller);
35
33
 
36
- const [meta, setMeta] = useState<ComputeMeta>();
34
+ const [meta, setMeta] = useState<ComputeNodeMeta>();
37
35
  useEffect(() => {
38
36
  let disposed = false;
39
37
  queueMicrotask(async () => {
@@ -43,6 +41,7 @@ export const useComputeNodeState = (shape: ComputeShape): ComputeNodeState => {
43
41
  if (disposed) {
44
42
  return;
45
43
  }
44
+
46
45
  setMeta(meta);
47
46
  });
48
47
 
@@ -56,7 +55,7 @@ export const useComputeNodeState = (shape: ComputeShape): ComputeNodeState => {
56
55
  }, [shape.node]);
57
56
 
58
57
  const subscribeToEventLog = useCallback(
59
- (cb: (event: ComputeEventPayload) => void) => {
58
+ (cb: (event: ComputeEvent) => void): (() => void) => {
60
59
  return controller.events.on((ev) => {
61
60
  if (ev.nodeId === shape.node) {
62
61
  cb(ev);
@@ -5,10 +5,9 @@
5
5
  import { useMemo } from 'react';
6
6
 
7
7
  import { type ComputeEdge, ComputeGraphModel, type ComputeNode, DEFAULT_INPUT, DEFAULT_OUTPUT } from '@dxos/conductor';
8
- import { ObjectId, Ref } from '@dxos/echo-schema';
8
+ import { Obj, Ref } from '@dxos/echo';
9
9
  import { invariant } from '@dxos/invariant';
10
- import { getSpace } from '@dxos/react-client/echo';
11
- import { type CanvasGraphModel, type Connection, type GraphMonitor } from '@dxos/react-ui-canvas-editor';
10
+ import { type CanvasBoard, type CanvasGraphModel, type GraphMonitor } from '@dxos/react-ui-canvas-editor';
12
11
  import { isNonNullable } from '@dxos/util';
13
12
 
14
13
  import { createComputeNode, isValidComputeNode } from '../graph';
@@ -19,7 +18,7 @@ import { type ComputeShape, type TriggerShape } from '../shapes';
19
18
  */
20
19
  export const mapEdge = (
21
20
  graph: CanvasGraphModel,
22
- { source, target, output = DEFAULT_OUTPUT, input = DEFAULT_INPUT }: Connection,
21
+ { source, target, output = DEFAULT_OUTPUT, input = DEFAULT_INPUT }: CanvasBoard.Connection,
23
22
  ): ComputeEdge => {
24
23
  const sourceNode = graph.findNode(source) as ComputeShape;
25
24
  const targetNode = graph.findNode(target) as ComputeShape;
@@ -27,7 +26,7 @@ export const mapEdge = (
27
26
  invariant(targetNode?.node);
28
27
 
29
28
  return {
30
- id: ObjectId.random(),
29
+ id: Obj.ID.random(),
31
30
  source: sourceNode.node,
32
31
  target: targetNode.node,
33
32
  output,
@@ -113,19 +112,21 @@ export const createComputeGraph = (graph?: CanvasGraphModel<ComputeShape>) => {
113
112
  const linkTriggerToCompute = (graph: ComputeGraphModel, computeNode: ComputeNode, triggerData: TriggerShape) => {
114
113
  const functionTrigger = triggerData.functionTrigger?.target;
115
114
  invariant(functionTrigger);
116
- functionTrigger.function = Ref.make(graph.root);
117
- functionTrigger.inputNodeId = computeNode.id;
115
+ Obj.update(functionTrigger, (functionTrigger) => {
116
+ functionTrigger.function = Ref.make(graph.root);
117
+ functionTrigger.inputNodeId = computeNode.id;
118
+ });
118
119
  };
119
120
 
120
121
  const deleteTriggerObjects = (computeGraph: ComputeGraphModel, deleted: CanvasGraphModel) => {
121
- const space = getSpace(computeGraph.root);
122
- if (!space) {
122
+ const db = Obj.getDatabase(computeGraph.root);
123
+ if (!db) {
123
124
  return;
124
125
  }
125
126
  for (const node of deleted.nodes) {
126
127
  if (node.type === 'trigger') {
127
128
  const trigger = node as TriggerShape;
128
- space.db.remove(trigger.functionTrigger!.target!);
129
+ db.remove(trigger.functionTrigger!.target!);
129
130
  }
130
131
  }
131
132
  };
package/src/json.test.ts CHANGED
@@ -2,15 +2,15 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
  import { describe, test } from 'vitest';
7
7
 
8
- import { BaseGraphEdge, BaseGraphNode } from '@dxos/graph';
8
+ import { Graph } from '@dxos/graph';
9
9
 
10
10
  import { createGptCircuit } from './testing';
11
11
 
12
12
  export const Shape = Schema.extend(
13
- BaseGraphNode,
13
+ Graph.Node,
14
14
  Schema.Struct({
15
15
  text: Schema.optional(Schema.String),
16
16
  guide: Schema.optional(Schema.Boolean),
@@ -19,7 +19,7 @@ export const Shape = Schema.extend(
19
19
  );
20
20
 
21
21
  export const Connection = Schema.extend(
22
- BaseGraphEdge,
22
+ Graph.Edge,
23
23
  Schema.Struct({
24
24
  input: Schema.optional(Schema.String),
25
25
  output: Schema.optional(Schema.String),
package/src/registry.ts CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  jsonTransformShape,
23
23
  notShape,
24
24
  orShape,
25
- queueShape,
25
+ feedShape,
26
26
  randomShape,
27
27
  reducerShape,
28
28
  scopeShape,
@@ -82,7 +82,7 @@ export const computeShapes: { title: string; shapes: ShapeDef[] }[] = [
82
82
  shapes: [
83
83
  //
84
84
  jsonShape,
85
- queueShape,
85
+ feedShape,
86
86
  threadShape,
87
87
  textShape,
88
88
  surfaceShape,
@@ -2,14 +2,14 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
  import { describe, test } from 'vitest';
7
7
 
8
- import { live } from '@dxos/client/echo';
9
- import { BaseGraphNode, Graph } from '@dxos/graph';
8
+ import { Graph } from '@dxos/graph';
10
9
  import {
10
+ CanvasBoard,
11
+ CanvasGraphModel,
11
12
  Polygon,
12
- Shape,
13
13
  createEllipse,
14
14
  createPath,
15
15
  createRectangle,
@@ -21,25 +21,25 @@ import { ComputeShape, createFunction, createSwitch } from './shapes';
21
21
 
22
22
  describe('compute', () => {
23
23
  test('model', ({ expect }) => {
24
- // const model = CanvasGraphModel.create<ComputeShape>();
24
+ const model = CanvasGraphModel.create<ComputeShape>();
25
25
  const node = createSwitch({ id: 'x', center: { x: 0, y: 0 }, size: { width: 80, height: 80 } });
26
26
  console.log(JSON.stringify(node, null, 2));
27
27
  expect(Schema.is(ComputeShape)(node)).toBe(true);
28
28
  expect(Schema.is(Polygon)(node)).toBe(true);
29
- expect(Schema.is(Shape)(node)).toBe(true);
30
- expect(Schema.is(BaseGraphNode)(node)).toBe(true);
29
+ expect(Schema.is(CanvasBoard.Shape)(node)).toBe(true);
30
+ expect(Schema.is(Graph.Node)(node)).toBe(true);
31
31
 
32
- const graph = live(Graph, { nodes: [], edges: [] });
33
- graph.nodes.push(node); // Throws.
32
+ const graph: Graph.Any = { nodes: [], edges: [] };
33
+ graph.nodes.push(node);
34
34
 
35
- // model.createNode(node);
36
- // console.log(JSON.stringify(model, null, 2));
35
+ model.createNode(node);
36
+ console.log(JSON.stringify(model, null, 2));
37
37
  });
38
38
  });
39
39
 
40
40
  describe('schema', () => {
41
41
  test('basic types', ({ expect }) => {
42
- const shapes: Shape[] = [];
42
+ const shapes: CanvasBoard.Shape[] = [];
43
43
  shapes.push(createRectangle({ id: 'shape-1', center: { x: 0, y: 0 }, size: { width: 80, height: 80 } }));
44
44
  shapes.push(createEllipse({ id: 'shape-2', center: { x: 0, y: 0 }, size: { width: 80, height: 80 } }));
45
45
  shapes.push(createFunction({ id: 'shape-3', center: { x: 0, y: 0 } }));
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
  import React from 'react';
7
7
 
8
8
  import { AppendInput } from '@dxos/conductor';