@dxos/assistant 0.8.3-main.672df60 → 0.8.3-staging.0fa589b

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 (43) hide show
  1. package/dist/lib/browser/index.mjs +149 -60
  2. package/dist/lib/browser/index.mjs.map +3 -3
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +155 -65
  5. package/dist/lib/node/index.cjs.map +3 -3
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +149 -60
  8. package/dist/lib/node-esm/index.mjs.map +3 -3
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/blueprint/ai.test.d.ts +2 -0
  11. package/dist/types/src/blueprint/ai.test.d.ts.map +1 -0
  12. package/dist/types/src/blueprint/blueprint.d.ts +16 -12
  13. package/dist/types/src/blueprint/blueprint.d.ts.map +1 -1
  14. package/dist/types/src/blueprint/logger.d.ts +16 -3
  15. package/dist/types/src/blueprint/logger.d.ts.map +1 -1
  16. package/dist/types/src/blueprint/machine.d.ts +37 -16
  17. package/dist/types/src/blueprint/machine.d.ts.map +1 -1
  18. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +1 -1
  19. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +31 -33
  20. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -1
  21. package/dist/types/src/extraction/extraction.d.ts +104 -100
  22. package/dist/types/src/extraction/extraction.d.ts.map +1 -1
  23. package/dist/types/src/extraction/quotes.d.ts.map +1 -1
  24. package/dist/types/src/research/graph.d.ts +5 -4
  25. package/dist/types/src/research/graph.d.ts.map +1 -1
  26. package/dist/types/src/session/session.d.ts +6 -6
  27. package/dist/types/src/session/session.d.ts.map +1 -1
  28. package/package.json +29 -20
  29. package/src/blueprint/ai.test.ts +156 -0
  30. package/src/blueprint/blueprint.test.ts +22 -20
  31. package/src/blueprint/blueprint.ts +18 -14
  32. package/src/blueprint/logger.ts +49 -3
  33. package/src/blueprint/machine.ts +69 -32
  34. package/src/blueprint/test-data.ts +4 -4
  35. package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +2 -2
  36. package/src/extraction/extraction-llm-function/extraction-llm-function.ts +2 -1
  37. package/src/extraction/quotes.ts +2 -1
  38. package/src/research/graph.ts +7 -9
  39. package/src/research/research.test.ts +9 -8
  40. package/src/research/research.ts +2 -2
  41. package/src/session/session.test.ts +10 -10
  42. package/src/session/session.ts +4 -3
  43. package/src/summarization/summarization.test.ts +17 -12
@@ -5,11 +5,11 @@
5
5
  import { Schema } from 'effect';
6
6
  import { describe, test } from 'vitest';
7
7
 
8
- import { AIServiceEdgeClient, ToolRegistry, ToolResult, createTool } from '@dxos/ai';
8
+ import { EdgeAiServiceClient, ToolRegistry, ToolResult, createTool } from '@dxos/ai';
9
9
  import { AI_SERVICE_ENDPOINT, EXA_API_KEY } from '@dxos/ai/testing';
10
10
  import { ArtifactId } from '@dxos/artifact';
11
+ import { Obj } from '@dxos/echo';
11
12
  import { EchoTestBuilder } from '@dxos/echo-db/testing';
12
- import { create } from '@dxos/echo-schema';
13
13
  import { DataType, DataTypes } from '@dxos/schema';
14
14
 
15
15
  import { BlueprintBuilder } from './blueprint';
@@ -23,7 +23,7 @@ import { createExaTool } from '../research/exa';
23
23
 
24
24
  // TODO(burdon): Don't run on CI.
25
25
  describe.skip('Blueprint', () => {
26
- const aiService = new AIServiceEdgeClient({
26
+ const aiClient = new EdgeAiServiceClient({
27
27
  endpoint: AI_SERVICE_ENDPOINT.REMOTE,
28
28
  defaultGenerationOptions: {
29
29
  // model: '@anthropic/claude-sonnet-4-20250514',
@@ -39,10 +39,10 @@ describe.skip('Blueprint', () => {
39
39
  .step('Write a pitch deck for the product')
40
40
  .build();
41
41
 
42
- const registry = new ToolRegistry([]);
43
- const machine = new BlueprintMachine(registry, blueprint);
42
+ const tools = new ToolRegistry([]);
43
+ const machine = new BlueprintMachine(tools, blueprint);
44
44
  setConsolePrinter(machine, true);
45
- await machine.runToCompletion({ aiService });
45
+ await machine.runToCompletion({ aiClient });
46
46
  });
47
47
 
48
48
  test('email bot', { timeout: 60_000 }, async () => {
@@ -96,10 +96,10 @@ describe.skip('Blueprint', () => {
96
96
  })
97
97
  .build();
98
98
 
99
- const registry = new ToolRegistry([replyTool, labelTool]);
100
- const machine = new BlueprintMachine(registry, blueprint);
99
+ const tools = new ToolRegistry([replyTool, labelTool]);
100
+ const machine = new BlueprintMachine(tools, blueprint);
101
101
  setConsolePrinter(machine);
102
- await machine.runToCompletion({ aiService, input: TEST_EMAILS[0] });
102
+ await machine.runToCompletion({ aiClient, input: TEST_EMAILS[0] });
103
103
  });
104
104
 
105
105
  test.only('research', { timeout: 120_000 }, async () => {
@@ -108,14 +108,14 @@ describe.skip('Blueprint', () => {
108
108
 
109
109
  const [org1] = [
110
110
  db.add(
111
- create(DataType.Organization, {
111
+ Obj.make(DataType.Organization, {
112
112
  name: 'Exa',
113
113
  website: 'https://exa.ai',
114
114
  description: 'An AI-powered search engine company building search infrastructure for AI agents',
115
115
  }),
116
116
  ),
117
117
  db.add(
118
- create(DataType.Organization, {
118
+ Obj.make(DataType.Organization, {
119
119
  name: 'Cresta',
120
120
  website: 'https://cresta.ai',
121
121
  description: 'A company that builds AI agents',
@@ -125,25 +125,27 @@ describe.skip('Blueprint', () => {
125
125
 
126
126
  await db.flush({ indexes: true });
127
127
 
128
- const webSearchTool = createExaTool({ apiKey: EXA_API_KEY });
129
- const localSearchTool = createLocalSearchTool(db);
130
- const graphWriterTool = createGraphWriterTool({ db, schemaTypes: DataTypes });
131
- const registry = new ToolRegistry([webSearchTool, localSearchTool, graphWriterTool]);
128
+ const [exa, localSearch, graphWriter] = [
129
+ createExaTool({ apiKey: EXA_API_KEY }),
130
+ createLocalSearchTool(db),
131
+ createGraphWriterTool({ db, schema: DataTypes }),
132
+ ];
132
133
 
133
134
  const blueprint = BlueprintBuilder.create()
134
135
  .step('Research founders of the organization. Do deep research.', {
135
- tools: [webSearchTool.id],
136
+ tools: [exa.id],
136
137
  })
137
138
  .step('Based on your research select matching entires that are already in the graph', {
138
- tools: [localSearchTool.id],
139
+ tools: [localSearch.id],
139
140
  })
140
141
  .step('Add researched data to the graph', {
141
- tools: [localSearchTool.id, graphWriterTool.id],
142
+ tools: [localSearch.id, graphWriter.id],
142
143
  })
143
144
  .build();
144
145
 
145
- const machine = new BlueprintMachine(registry, blueprint);
146
+ const tools = new ToolRegistry([exa, localSearch, graphWriter]);
147
+ const machine = new BlueprintMachine(tools, blueprint);
146
148
  setConsolePrinter(machine, true);
147
- await machine.runToCompletion({ aiService, input: org1 });
149
+ await machine.runToCompletion({ aiClient, input: org1 });
148
150
  });
149
151
  });
@@ -4,26 +4,30 @@
4
4
 
5
5
  import { Schema } from 'effect';
6
6
 
7
- import { Obj, Type } from '@dxos/echo';
8
- import { ObjectId } from '@dxos/keys';
7
+ import { Key, Obj, Type } from '@dxos/echo';
9
8
 
10
- export const BlueprintStepSchema = Schema.Struct({
11
- id: ObjectId,
9
+ export const BlueprintStep = Schema.Struct({
10
+ id: Key.ObjectId,
12
11
  instructions: Schema.String,
13
- tools: Schema.Array(Schema.String),
12
+ tools: Schema.optional(Schema.Array(Schema.String)),
14
13
  });
15
- export type BlueprintStep = Schema.Schema.Type<typeof BlueprintStepSchema>;
14
+ export interface BlueprintStep extends Schema.Schema.Type<typeof BlueprintStep> {}
16
15
 
17
- export const BlueprintSchema = Schema.Struct({
18
- steps: Schema.Array(BlueprintStepSchema.pipe(Schema.omit('id'))),
16
+ export const BlueprintDefinition = Schema.Struct({
17
+ steps: Schema.Array(BlueprintStep.pipe(Schema.omit('id'))),
19
18
  });
20
- export type BlueprintDef = Schema.Schema.Type<typeof BlueprintSchema>;
19
+ export interface BlueprintDefinition extends Schema.Schema.Type<typeof BlueprintDefinition> {}
21
20
 
22
21
  export const Blueprint = Schema.Struct({
23
22
  name: Schema.optional(Schema.String),
24
- steps: Schema.Array(BlueprintStepSchema),
25
- }).pipe(Type.Obj({ typename: 'dxos.org/type/Blueprint', version: '0.1.0' }));
26
- export type Blueprint = Schema.Schema.Type<typeof Blueprint>;
23
+ steps: Schema.Array(BlueprintStep),
24
+ }).pipe(
25
+ Type.Obj({
26
+ typename: 'dxos.org/type/Blueprint',
27
+ version: '0.1.0',
28
+ }),
29
+ );
30
+ export interface Blueprint extends Schema.Schema.Type<typeof Blueprint> {}
27
31
 
28
32
  /**
29
33
  * Blueprint builder API.
@@ -36,7 +40,7 @@ export namespace BlueprintBuilder {
36
40
 
37
41
  step(instructions: string, options?: { tools?: string[] }): Builder {
38
42
  this._steps.push({
39
- id: ObjectId.random(),
43
+ id: Key.ObjectId.random(),
40
44
  instructions,
41
45
  tools: options?.tools ?? [],
42
46
  });
@@ -57,7 +61,7 @@ export namespace BlueprintParser {
57
61
  export const create = () => new Parser();
58
62
 
59
63
  class Parser {
60
- parse({ steps }: BlueprintDef): Blueprint {
64
+ parse({ steps }: BlueprintDefinition): Blueprint {
61
65
  const builder = BlueprintBuilder.create();
62
66
  for (const step of steps) {
63
67
  builder.step(step.instructions, {
@@ -7,16 +7,34 @@ import chalk from 'chalk';
7
7
 
8
8
  import { ConsolePrinter } from '@dxos/ai';
9
9
  import { type CleanupFn, combine } from '@dxos/async';
10
+ import { log } from '@dxos/log';
10
11
 
11
12
  import { type Blueprint } from './blueprint';
12
- import { type BlueprintMachine, type BlueprintMachineState } from './machine';
13
+ import {
14
+ type BlueprintEvent,
15
+ type BlueprintLogger,
16
+ type BlueprintMachine,
17
+ type BlueprintMachineState,
18
+ } from './machine';
13
19
 
14
20
  /* eslint-disable no-console */
15
21
 
16
22
  // Force chalk colors on for tests.
17
23
  chalk.level = 2;
18
24
 
19
- export class Logger {
25
+ // TODO(burdon): Factor out.
26
+ type ConsoleLogSignature = (message: string, arg?: any) => void;
27
+
28
+ interface Logger {
29
+ log: ConsoleLogSignature;
30
+ }
31
+
32
+ const DEFAULT_LOGGER: Logger = { log: log.info };
33
+
34
+ /**
35
+ * Reactive bufferedlogger.
36
+ */
37
+ export class BufferedLogger implements Logger {
20
38
  private _messages = signal<string[]>([]);
21
39
 
22
40
  get messages(): ReadonlySignal<string[]> {
@@ -32,7 +50,35 @@ export class Logger {
32
50
  }
33
51
  }
34
52
 
35
- export const setLogger = (machine: BlueprintMachine, logger: Logger): CleanupFn => {
53
+ // TODO(burdon): Reconcile with ConsolePrinter.
54
+ export class BlueprintLoggerAdapter implements BlueprintLogger {
55
+ constructor(private readonly logger: Logger = DEFAULT_LOGGER) {}
56
+
57
+ log(event: BlueprintEvent) {
58
+ switch (event.type) {
59
+ case 'begin':
60
+ this.logger.log('begin', { invocationId: event.invocationId });
61
+ break;
62
+ case 'end':
63
+ this.logger.log('end', { invocationId: event.invocationId });
64
+ break;
65
+ case 'step-start':
66
+ this.logger.log('step-start', { invocationId: event.invocationId, step: event.step });
67
+ break;
68
+ case 'step-complete':
69
+ this.logger.log('step-complete', { invocationId: event.invocationId, step: event.step });
70
+ break;
71
+ case 'message':
72
+ this.logger.log('message', { invocationId: event.invocationId, message: event.message });
73
+ break;
74
+ case 'block':
75
+ this.logger.log('block', { invocationId: event.invocationId, block: event.block });
76
+ break;
77
+ }
78
+ }
79
+ }
80
+
81
+ export const setLogger = (machine: BlueprintMachine, logger: BufferedLogger): CleanupFn => {
36
82
  return combine(
37
83
  machine.begin.on(() => {
38
84
  logger.log('Starting...');
@@ -6,7 +6,7 @@ import { Match, Schema } from 'effect';
6
6
 
7
7
  import {
8
8
  createTool,
9
- type AIServiceClient,
9
+ type AiServiceClient,
10
10
  Message,
11
11
  type MessageContentBlock,
12
12
  ToolResult,
@@ -14,7 +14,7 @@ import {
14
14
  type ToolRegistry,
15
15
  } from '@dxos/ai';
16
16
  import { Event } from '@dxos/async';
17
- import { create } from '@dxos/echo-schema';
17
+ import { Key, Obj } from '@dxos/echo';
18
18
  import { type ObjectId } from '@dxos/keys';
19
19
  import { log } from '@dxos/log';
20
20
  import { isNonNullable } from '@dxos/util';
@@ -22,6 +22,17 @@ import { isNonNullable } from '@dxos/util';
22
22
  import type { Blueprint, BlueprintStep } from './blueprint';
23
23
  import { AISession } from '../session';
24
24
 
25
+ const SYSTEM_PROMPT = `
26
+ You are a smart Rule-Following Agent.
27
+ Rule-Following Agent executes the command that the user sent in the last message.
28
+ After doing the work, the Rule-Following Agent calls report tool.
29
+ If the Rule-Following agent believes that no action is needed, it calls the report tool with "skipped" status.
30
+ If the Rule-Following Agent is unable to perform the task, it calls the report tool with "bail" status.
31
+ Rule-Following Agent explains the reason it is unable to perform the task before bailing.
32
+ The Rule-Following Agent can express creativity and imagination in the way it performs the task.
33
+ The Rule-Following Agent precisely follows the instructions.
34
+ `;
35
+
25
36
  export type BlueprintTraceStep = {
26
37
  status: 'done' | 'bailed' | 'skipped';
27
38
  stepId: ObjectId;
@@ -41,7 +52,7 @@ const INITIAL_STATE: BlueprintMachineState = {
41
52
  };
42
53
 
43
54
  type ExecutionOptions = {
44
- aiService: AIServiceClient;
55
+ aiClient: AiServiceClient;
45
56
 
46
57
  /**
47
58
  * Input to the blueprint.
@@ -49,6 +60,18 @@ type ExecutionOptions = {
49
60
  input?: unknown;
50
61
  };
51
62
 
63
+ export type BlueprintEvent =
64
+ | { type: 'begin'; invocationId: string }
65
+ | { type: 'end'; invocationId: string }
66
+ | { type: 'step-start'; invocationId: string; step: BlueprintStep }
67
+ | { type: 'step-complete'; invocationId: string; step: BlueprintStep }
68
+ | { type: 'message'; invocationId: string; message: Message }
69
+ | { type: 'block'; invocationId: string; block: MessageContentBlock };
70
+
71
+ export interface BlueprintLogger {
72
+ log(event: BlueprintEvent): void;
73
+ }
74
+
52
75
  /**
53
76
  * Blueprint state machine.
54
77
  */
@@ -60,46 +83,67 @@ export class BlueprintMachine {
60
83
  public readonly message = new Event<Message>();
61
84
  public readonly block = new Event<MessageContentBlock>();
62
85
 
63
- state: BlueprintMachineState = structuredClone(INITIAL_STATE);
86
+ // TODO(burdon): Replace events with logger?
87
+ private logger?: BlueprintLogger;
88
+
89
+ private _state: BlueprintMachineState = structuredClone(INITIAL_STATE);
64
90
 
65
91
  constructor(
66
92
  readonly registry: ToolRegistry,
67
93
  readonly blueprint: Blueprint,
68
94
  ) {}
69
95
 
96
+ get state(): BlueprintMachineState {
97
+ return this._state;
98
+ }
99
+
100
+ setLogger(logger: BlueprintLogger): this {
101
+ this.logger = logger;
102
+ return this;
103
+ }
104
+
70
105
  async runToCompletion(options: ExecutionOptions): Promise<void> {
71
- log.info('runToCompletion', options);
106
+ const invocationId = Key.ObjectId.random();
107
+ log.info('runToCompletion', { invocationId, options });
72
108
 
73
109
  this.begin.emit();
110
+ this.logger?.log({ type: 'begin', invocationId });
111
+
74
112
  let firstStep = true;
75
- while (this.state.state !== 'done') {
113
+ while (this._state.state !== 'done') {
76
114
  const input = firstStep ? options.input : undefined;
77
-
78
115
  firstStep = false;
79
- this.state = await this._execStep(this.state, {
80
- input,
81
- aiService: options.aiService,
82
- });
83
116
 
84
- this.stepComplete.emit(this.blueprint.steps.find((step) => step.id === this.state.trace.at(-1)?.stepId)!);
117
+ this._state = await this._execStep(invocationId, this._state, { input, aiClient: options.aiClient });
118
+
119
+ const step = this.blueprint.steps.find((step) => step.id === this._state.trace.at(-1)?.stepId)!;
120
+ this.stepComplete.emit(step);
121
+ this.logger?.log({ type: 'step-complete', invocationId, step });
85
122
 
86
- if (this.state.state === 'bail') {
123
+ if (this._state.state === 'bail') {
87
124
  throw new Error('Agent unable to follow the blueprint');
88
125
  }
89
126
  }
90
127
 
91
128
  this.end.emit();
129
+ this.logger?.log({ type: 'end', invocationId });
92
130
  }
93
131
 
94
- private async _execStep(state: BlueprintMachineState, options: ExecutionOptions): Promise<BlueprintMachineState> {
95
- const prevStep = this.blueprint.steps.findIndex((step) => step.id === this.state.trace.at(-1)?.stepId);
132
+ private async _execStep(
133
+ invocationId: string,
134
+ state: BlueprintMachineState,
135
+ options: ExecutionOptions,
136
+ ): Promise<BlueprintMachineState> {
137
+ const prevStep = this.blueprint.steps.findIndex((step) => step.id === this._state.trace.at(-1)?.stepId);
96
138
  if (prevStep === this.blueprint.steps.length - 1) {
97
139
  throw new Error('Done execution blueprint');
98
140
  }
99
141
 
100
142
  const nextStep = this.blueprint.steps[prevStep + 1];
101
143
  const onLastStep = prevStep === this.blueprint.steps.length - 2;
144
+
102
145
  this.stepStart.emit(nextStep);
146
+ this.logger?.log({ type: 'step-start', invocationId, step: nextStep });
103
147
 
104
148
  const ReportSchema = Schema.Struct({
105
149
  status: Schema.Literal('done', 'bailed', 'skipped').annotations({
@@ -113,7 +157,7 @@ export class BlueprintMachine {
113
157
 
114
158
  const report = createTool('system', {
115
159
  name: 'report',
116
- description: 'This tool reports that the agent has completed the task or is unable to do so',
160
+ description: 'This tool reports that the agent has completed the task or is unable to do so.',
117
161
  schema: ReportSchema,
118
162
  execute: async (input) => ToolResult.Break(input),
119
163
  });
@@ -128,38 +172,31 @@ export class BlueprintMachine {
128
172
 
129
173
  const inputMessages = options.input
130
174
  ? [
131
- create(Message, {
175
+ Obj.make(Message, {
132
176
  role: 'user',
133
177
  content: [taggedDataBlock('input', options.input)],
134
178
  }),
135
179
  ]
136
180
  : [];
137
- inputMessages.forEach((message) => this.message.emit(message));
181
+ inputMessages.forEach((message) => {
182
+ this.message.emit(message);
183
+ this.logger?.log({ type: 'message', invocationId, message });
184
+ });
138
185
 
139
186
  // TODO(wittjosiah): Warn if tool is not found.
140
- const tools = nextStep.tools.map((tool) => this.registry.get(tool)).filter(isNonNullable);
187
+ const tools = nextStep.tools?.map((tool) => this.registry.get(tool)).filter(isNonNullable) ?? [];
141
188
  const messages = await session.run({
142
- systemPrompt: `
143
- You are a smart Rule-Following Agent.
144
- Rule-Following Agent executes the command that the user sent in the last message.
145
- After doing the work, the Rule-Following Agent calls report tool.
146
- If the Rule-Following agent believes that no action is needed, it calls the report tool with "skipped" status.
147
- If the Rule-Following Agent is unable to perform the task, it calls the report tool with "bail" status.
148
- Rule-Following Agent explains the reason it is unable to perform the task before bailing.
149
- The Rule-Following Agent can express creativity and imagination in the way it performs the task.
150
- The Rule-Following Agent precisely follows the instructions.
151
- `,
189
+ systemPrompt: SYSTEM_PROMPT,
152
190
  history: [...state.history, ...inputMessages],
153
191
  tools: [...tools, report],
154
192
  artifacts: [],
155
- client: options.aiService,
193
+ client: options.aiClient,
156
194
  prompt: nextStep.instructions,
157
195
  });
158
196
 
159
197
  const { messages: trimmedHistory, call: lastBlock } = popLastToolCall(messages);
160
-
161
198
  if (!lastBlock) {
162
- // TODO(dmaretskyi): Handle this with grace
199
+ // TODO(dmaretskyi): Handle this with grace.
163
200
  throw new Error('Agent did not call the report tool');
164
201
  }
165
202
 
@@ -2,12 +2,12 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { create } from '@dxos/echo-schema';
5
+ import { Obj } from '@dxos/echo';
6
6
  import { DataType } from '@dxos/schema';
7
7
 
8
8
  // TODO(burdon): Convert to queue.
9
9
  export const TEST_EMAILS: DataType.Message[] = [
10
- create(DataType.Message, {
10
+ Obj.make(DataType.Message, {
11
11
  properties: {
12
12
  subject: 'Introduction email',
13
13
  },
@@ -22,7 +22,7 @@ export const TEST_EMAILS: DataType.Message[] = [
22
22
  ],
23
23
  created: new Date().toISOString(),
24
24
  }),
25
- create(DataType.Message, {
25
+ Obj.make(DataType.Message, {
26
26
  properties: {
27
27
  subject: 'Question about integration',
28
28
  },
@@ -37,7 +37,7 @@ export const TEST_EMAILS: DataType.Message[] = [
37
37
  ],
38
38
  created: new Date().toISOString(),
39
39
  }),
40
- create(DataType.Message, {
40
+ Obj.make(DataType.Message, {
41
41
  properties: {
42
42
  subject: 'MAKE MONEY FAST!!!',
43
43
  },
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { describe, test, beforeAll } from 'vitest';
6
6
 
7
- import { AIServiceEdgeClient } from '@dxos/ai';
7
+ import { EdgeAiServiceClient } from '@dxos/ai';
8
8
  import { AI_SERVICE_ENDPOINT } from '@dxos/ai/testing';
9
9
  import { FunctionExecutor, ServiceContainer } from '@dxos/functions';
10
10
  import { log } from '@dxos/log';
@@ -21,7 +21,7 @@ describe.skip('LLM EntityExtraction', () => {
21
21
  executor = new FunctionExecutor(
22
22
  new ServiceContainer().setServices({
23
23
  ai: {
24
- client: new AIServiceEdgeClient({
24
+ client: new EdgeAiServiceClient({
25
25
  endpoint: AI_SERVICE_ENDPOINT.REMOTE,
26
26
  defaultGenerationOptions: {
27
27
  // model: '@anthropic/claude-sonnet-4-20250514',
@@ -3,6 +3,7 @@
3
3
  //
4
4
 
5
5
  import { Message } from '@dxos/ai';
6
+ import { Obj } from '@dxos/echo';
6
7
  import { create } from '@dxos/echo-schema';
7
8
  import { AiService, defineFunction, type FunctionDefinition } from '@dxos/functions';
8
9
  import { DataType } from '@dxos/schema';
@@ -27,7 +28,7 @@ export const extractionAnthropicFn: FunctionDefinition<ExtractionInput, Extracti
27
28
  client: ai.client,
28
29
  systemPrompt: PROMPT,
29
30
  history: [
30
- create(Message, {
31
+ Obj.make(Message, {
31
32
  role: 'user',
32
33
  content: [
33
34
  {
@@ -4,8 +4,9 @@
4
4
 
5
5
  import { Schema } from 'effect';
6
6
 
7
+ import { Query, Filter } from '@dxos/echo';
7
8
  import { type EchoDatabase } from '@dxos/echo-db';
8
- import { Filter, ObjectId, Query } from '@dxos/echo-schema';
9
+ import { ObjectId } from '@dxos/echo-schema';
9
10
  import { DXN } from '@dxos/keys';
10
11
  import { log } from '@dxos/log';
11
12
 
@@ -6,6 +6,7 @@ import { Schema, identity, Option, SchemaAST } from 'effect';
6
6
 
7
7
  import { createTool, ToolResult } from '@dxos/ai';
8
8
  import type { Obj, Relation } from '@dxos/echo';
9
+ import { Query, Filter } from '@dxos/echo';
9
10
  import { type EchoDatabase, type Queue } from '@dxos/echo-db';
10
11
  import { isEncodedReference } from '@dxos/echo-protocol';
11
12
  import {
@@ -13,13 +14,10 @@ import {
13
14
  getSchemaTypename,
14
15
  getTypeAnnotation,
15
16
  getTypeIdentifierAnnotation,
16
- type AnyEchoObject,
17
17
  create,
18
- Filter,
19
18
  getEntityKind,
20
19
  getSchemaDXN,
21
20
  ObjectId,
22
- Query,
23
21
  ReferenceAnnotationId,
24
22
  type BaseObject,
25
23
  RelationSourceDXNId,
@@ -319,21 +317,21 @@ const preprocessSchema = (schema: Schema.Schema.AnyNoContext) => {
319
317
  export const createGraphWriterTool = ({
320
318
  db,
321
319
  queue,
322
- schemaTypes,
320
+ schema,
323
321
  onDone = async (x) => x,
324
322
  }: {
325
323
  db: EchoDatabase;
326
324
  queue?: Queue;
327
- schemaTypes: Schema.Schema.AnyNoContext[];
328
- onDone?: (data: AnyEchoObject[]) => Promise<any>;
325
+ schema: Schema.Schema.AnyNoContext[];
326
+ onDone?: (data: Obj.Any[]) => Promise<any>;
329
327
  }) => {
330
328
  return createTool('graph', {
331
329
  name: 'writer',
332
330
  description: 'Write to the local graph database',
333
- schema: createExtractionSchema(schemaTypes),
331
+ schema: createExtractionSchema(schema),
334
332
  execute: async (input) => {
335
- const data = await sanitizeObjects(schemaTypes, input as any, db, queue);
336
- return ToolResult.Success(await onDone(data as AnyEchoObject[]));
333
+ const data = await sanitizeObjects(schema, input as any, db, queue);
334
+ return ToolResult.Success(await onDone(data as Obj.Any[]));
337
335
  },
338
336
  });
339
337
  };
@@ -5,13 +5,13 @@
5
5
  import { inspect } from 'node:util';
6
6
  import { beforeAll, describe, test } from 'vitest';
7
7
 
8
- import { AIServiceEdgeClient, OllamaClient, structuredOutputParser } from '@dxos/ai';
8
+ import { EdgeAiServiceClient, OllamaAiServiceClient, structuredOutputParser } from '@dxos/ai';
9
9
  import { AI_SERVICE_ENDPOINT, EXA_API_KEY } from '@dxos/ai/testing';
10
+ import { Obj } from '@dxos/echo';
10
11
  import { type EchoDatabase } from '@dxos/echo-db';
11
12
  import { EchoTestBuilder } from '@dxos/echo-db/testing';
12
13
  import { getSchemaDXN } from '@dxos/echo-schema';
13
14
  import { ConfiguredCredentialsService, FunctionExecutor, ServiceContainer, TracingService } from '@dxos/functions';
14
- import { live } from '@dxos/live-object';
15
15
  import { DataType, DataTypes } from '@dxos/schema';
16
16
 
17
17
  import { createExtractionSchema, getSanitizedSchemaName } from './graph';
@@ -20,7 +20,7 @@ import { researchFn } from './research';
20
20
  const REMOTE_AI = true;
21
21
  const MOCK_SEARCH = false;
22
22
 
23
- describe('Research', () => {
23
+ describe.skip('Research', () => {
24
24
  let builder: EchoTestBuilder;
25
25
  let db: EchoDatabase;
26
26
  let executor: FunctionExecutor;
@@ -28,21 +28,22 @@ describe('Research', () => {
28
28
  beforeAll(async () => {
29
29
  // TODO(dmaretskyi): Helper to scaffold this from a config.
30
30
  builder = await new EchoTestBuilder().open();
31
- const { db: db1 } = await builder.createDatabase({ indexing: { vector: true } });
32
- db = db1;
31
+
32
+ db = (await builder.createDatabase({ indexing: { vector: true } })).db;
33
33
  db.graph.schemaRegistry.addSchema(DataTypes);
34
+
34
35
  executor = new FunctionExecutor(
35
36
  new ServiceContainer().setServices({
36
37
  ai: {
37
38
  client: REMOTE_AI
38
- ? new AIServiceEdgeClient({
39
+ ? new EdgeAiServiceClient({
39
40
  endpoint: AI_SERVICE_ENDPOINT.REMOTE,
40
41
  defaultGenerationOptions: {
41
42
  // model: '@anthropic/claude-sonnet-4-20250514',
42
43
  model: '@anthropic/claude-3-5-sonnet-20241022',
43
44
  },
44
45
  })
45
- : new OllamaClient({
46
+ : new OllamaAiServiceClient({
46
47
  overrides: {
47
48
  model: 'llama3.1:8b',
48
49
  },
@@ -57,7 +58,7 @@ describe('Research', () => {
57
58
 
58
59
  test('should generate a research report', { timeout: 300_000 }, async () => {
59
60
  db.add(
60
- live(DataType.Organization, {
61
+ Obj.make(DataType.Organization, {
61
62
  name: 'Notion',
62
63
  website: 'https://www.notion.com',
63
64
  }),
@@ -41,7 +41,7 @@ export const researchFn = defineFunction({
41
41
  const ai = context.getService(AiService);
42
42
  const credentials = context.getService(CredentialsService);
43
43
  const { db } = context.getService(DatabaseService);
44
- // const queues = context.getService(QueuesService);
44
+ // const queues = context.getService(QueueService);
45
45
  const tracing = context.getService(TracingService);
46
46
 
47
47
  tracing.write(create(AgentStatusReport, { message: 'Researching...' }));
@@ -60,7 +60,7 @@ export const researchFn = defineFunction({
60
60
  });
61
61
  session.streamEvent.on((event) => log('stream', { event }));
62
62
 
63
- const graphWriteTool = createGraphWriterTool({ db, schemaTypes: DataTypes });
63
+ const graphWriteTool = createGraphWriterTool({ db, schema: DataTypes });
64
64
  log.info('graphWriteTool', { schema: graphWriteTool.parameters });
65
65
 
66
66
  // TODO(dmaretskyi): Consider adding this pattern as the "Graph" output mode for the session.