@dxos/assistant 0.8.4-main.84f28bd → 0.8.4-main.b97322e

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 (82) hide show
  1. package/dist/lib/browser/index.mjs +623 -811
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +623 -811
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/context/binder.d.ts +4 -4
  8. package/dist/types/src/context/binder.d.ts.map +1 -1
  9. package/dist/types/src/context/binding.d.ts +24 -6
  10. package/dist/types/src/context/binding.d.ts.map +1 -1
  11. package/dist/types/src/conversation/conversation.d.ts +12 -18
  12. package/dist/types/src/conversation/conversation.d.ts.map +1 -1
  13. package/dist/types/src/errors.d.ts +38 -0
  14. package/dist/types/src/errors.d.ts.map +1 -0
  15. package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +1 -1
  16. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +127 -33
  17. package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -1
  18. package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts +1 -1
  19. package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts.map +1 -1
  20. package/dist/types/src/extraction/extraction.d.ts +100 -42
  21. package/dist/types/src/extraction/extraction.d.ts.map +1 -1
  22. package/dist/types/src/functions/index.d.ts +2 -0
  23. package/dist/types/src/functions/index.d.ts.map +1 -0
  24. package/dist/types/src/functions/services.d.ts +6 -0
  25. package/dist/types/src/functions/services.d.ts.map +1 -0
  26. package/dist/types/src/index.d.ts +2 -2
  27. package/dist/types/src/index.d.ts.map +1 -1
  28. package/dist/types/src/research/exa.d.ts +10 -5
  29. package/dist/types/src/research/exa.d.ts.map +1 -1
  30. package/dist/types/src/research/graph.d.ts +18 -8
  31. package/dist/types/src/research/graph.d.ts.map +1 -1
  32. package/dist/types/src/research/research.d.ts +1 -1
  33. package/dist/types/src/research/research.d.ts.map +1 -1
  34. package/dist/types/src/session/session.d.ts +170 -193
  35. package/dist/types/src/session/session.d.ts.map +1 -1
  36. package/dist/types/src/session/version-pin.d.ts +2 -2
  37. package/dist/types/src/session/version-pin.d.ts.map +1 -1
  38. package/dist/types/src/templates/index.d.ts +2 -0
  39. package/dist/types/src/templates/index.d.ts.map +1 -0
  40. package/dist/types/src/templates/prompt.d.ts +30 -0
  41. package/dist/types/src/templates/prompt.d.ts.map +1 -0
  42. package/dist/types/src/types.d.ts +10 -0
  43. package/dist/types/src/types.d.ts.map +1 -1
  44. package/dist/types/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +29 -21
  46. package/src/context/binder.ts +6 -4
  47. package/src/context/binding.ts +4 -3
  48. package/src/conversation/conversation.ts +54 -61
  49. package/src/errors.ts +10 -0
  50. package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +6 -18
  51. package/src/extraction/extraction-llm-function/extraction-llm-function.ts +18 -14
  52. package/src/extraction/extraction-ner-function/extraction-ner-function.ts +6 -3
  53. package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +2 -2
  54. package/src/extraction/extraction-ner-function/named-entity-recognition.ts +1 -1
  55. package/src/functions/index.ts +5 -0
  56. package/src/functions/services.ts +139 -0
  57. package/src/index.ts +2 -2
  58. package/src/research/exa.ts +56 -59
  59. package/src/research/graph.test.ts +50 -1
  60. package/src/research/graph.ts +85 -53
  61. package/src/research/instructions-research.tpl +1 -0
  62. package/src/research/research.test.ts +27 -27
  63. package/src/research/research.ts +50 -53
  64. package/src/session/__snapshots__/session.test.ts.snap +32 -0
  65. package/src/session/session.test.ts +90 -55
  66. package/src/session/session.ts +215 -461
  67. package/src/session/version-pin.test.ts +2 -21
  68. package/src/session/version-pin.ts +5 -5
  69. package/src/summarization/summarization.test.ts +75 -88
  70. package/src/templates/assistant.tpl +111 -0
  71. package/src/templates/index.ts +5 -0
  72. package/src/templates/prompt.ts +45 -0
  73. package/src/types.ts +40 -1
  74. package/dist/types/src/blueprint/blueprint.d.ts +0 -41
  75. package/dist/types/src/blueprint/blueprint.d.ts.map +0 -1
  76. package/dist/types/src/blueprint/index.d.ts +0 -3
  77. package/dist/types/src/blueprint/index.d.ts.map +0 -1
  78. package/dist/types/src/blueprint/registry.d.ts +0 -7
  79. package/dist/types/src/blueprint/registry.d.ts.map +0 -1
  80. package/src/blueprint/blueprint.ts +0 -75
  81. package/src/blueprint/index.ts +0 -6
  82. package/src/blueprint/registry.ts +0 -15
@@ -1,72 +1,3 @@
1
- // src/blueprint/blueprint.ts
2
- import { Schema } from "effect";
3
- import { ToolId } from "@dxos/ai";
4
- import { Type } from "@dxos/echo";
5
- import { LabelAnnotation } from "@dxos/echo-schema";
6
- var Blueprint = Schema.Struct({
7
- /**
8
- * Global registry ID.
9
- * NOTE: Once a blueprint has been cloned from the registry, its stored definition may converge,
10
- * but the `key` property refers to the original registry entry.
11
- */
12
- // TODO(burdon): Create Format type.
13
- key: Schema.String.annotations({
14
- description: "Unique registration key for the blueprint"
15
- }),
16
- /**
17
- * Human-readable name of the blueprint.
18
- */
19
- name: Schema.String.annotations({
20
- description: "Human-readable name of the blueprint"
21
- }),
22
- /**
23
- * Description of the blueprint's purpose and functionality.
24
- */
25
- description: Schema.optional(Schema.String).annotations({
26
- description: "Description of the blueprint's purpose and functionality"
27
- }),
28
- /**
29
- * Instructions that guide the AI assistant's behavior and responses.
30
- * These are system prompts or guidelines that the AI should follow.
31
- */
32
- instructions: Schema.String.annotations({
33
- description: "Instructions that guide the AI assistant's behavior and responses"
34
- }),
35
- /**
36
- * Array of tools that the AI assistant can use when this blueprint is active.
37
- */
38
- tools: Schema.Array(ToolId).annotations({
39
- description: "Array of tools that the AI assistant can use when this blueprint is active"
40
- }),
41
- /**
42
- * Array of artifacts that the AI assistant can create or modify.
43
- */
44
- artifacts: Schema.Array(Schema.String).annotations({
45
- description: "Ids of artifact definitions that should be pulled into the blueprint"
46
- })
47
- }).pipe(
48
- Type.Obj({
49
- // TODO(burdon): Is this a DXN? Need to create a Format type for these IDs.
50
- typename: "dxos.org/type/Blueprint",
51
- version: "0.1.0"
52
- }),
53
- // TODO(burdon): Move to main API.
54
- LabelAnnotation.set([
55
- "name"
56
- ])
57
- );
58
-
59
- // src/blueprint/registry.ts
60
- var BlueprintRegistry = class {
61
- constructor(_blueprints) {
62
- this._blueprints = _blueprints;
63
- this._blueprints.sort(({ name: a }, { name: b }) => a.localeCompare(b));
64
- }
65
- query() {
66
- return this._blueprints;
67
- }
68
- };
69
-
70
1
  // src/context/binder.ts
71
2
  import { computed } from "@preact/signals-core";
72
3
  import { Array as Array2, pipe } from "effect";
@@ -74,19 +5,20 @@ import { Obj } from "@dxos/echo";
74
5
  import { ComplexSet } from "@dxos/util";
75
6
 
76
7
  // src/context/binding.ts
77
- import { Schema as Schema2 } from "effect";
78
- import { Type as Type2 } from "@dxos/echo";
79
- var ContextBinding = Schema2.Struct({
80
- blueprints: Schema2.Struct({
81
- added: Schema2.Array(Type2.Ref(Blueprint)),
82
- removed: Schema2.Array(Type2.Ref(Blueprint))
8
+ import { Schema } from "effect";
9
+ import { Blueprint } from "@dxos/blueprints";
10
+ import { Type } from "@dxos/echo";
11
+ var ContextBinding = Schema.Struct({
12
+ blueprints: Schema.Struct({
13
+ added: Schema.Array(Type.Ref(Blueprint.Blueprint)),
14
+ removed: Schema.Array(Type.Ref(Blueprint.Blueprint))
83
15
  }),
84
16
  // TODO(burdon): Type.Expando => Type.Obj (or Obj.Any?)
85
- objects: Schema2.Struct({
86
- added: Schema2.Array(Type2.Ref(Type2.Expando)),
87
- removed: Schema2.Array(Type2.Ref(Type2.Expando))
17
+ objects: Schema.Struct({
18
+ added: Schema.Array(Type.Ref(Type.Expando)),
19
+ removed: Schema.Array(Type.Ref(Type.Expando))
88
20
  })
89
- }).pipe(Type2.Obj({
21
+ }).pipe(Type.Obj({
90
22
  typename: "dxos.org/type/ContextBinding",
91
23
  version: "0.1.0"
92
24
  }));
@@ -163,479 +95,200 @@ var Bindings = class {
163
95
  };
164
96
 
165
97
  // src/conversation/conversation.ts
166
- import { Message as Message2 } from "@dxos/ai";
98
+ import { Effect as Effect2 } from "effect";
167
99
  import { Event as Event2 } from "@dxos/async";
168
- import { Obj as Obj3, Ref } from "@dxos/echo";
169
- import { AiService, ToolResolverService } from "@dxos/functions";
170
- import { log as log2 } from "@dxos/log";
171
- import { isNonNullable } from "@dxos/util";
100
+ import { Obj as Obj3 } from "@dxos/echo";
101
+ import { DatabaseService as DatabaseService2 } from "@dxos/functions";
102
+ import { DataType as DataType2 } from "@dxos/schema";
172
103
 
173
104
  // src/session/session.ts
174
- import { Array as Array3, Option, pipe as pipe2, Schema as Schema4 } from "effect";
175
- import { AgentStatusReport, isToolUse, runTools, structuredOutputParser, Message, MixedStreamParser, ToolResult, createTool } from "@dxos/ai";
176
- import { Event, synchronized } from "@dxos/async";
105
+ import { AiLanguageModel, AiToolkit } from "@effect/ai";
106
+ import { Chunk, Context, Effect, Option, pipe as pipe2, Stream } from "effect";
107
+ import { Array as Array3, String } from "effect";
108
+ import { AiParser, AiPreprocessor, getToolCalls, runTool, ToolExecutionService, ToolResolverService } from "@dxos/ai";
109
+ import { Event } from "@dxos/async";
110
+ import { todo } from "@dxos/debug";
177
111
  import { Obj as Obj2 } from "@dxos/echo";
178
112
  import { ObjectVersion } from "@dxos/echo-db";
179
- import { create } from "@dxos/echo-schema";
180
- import { invariant } from "@dxos/invariant";
113
+ import { DatabaseService } from "@dxos/functions";
181
114
  import { log } from "@dxos/log";
115
+ import { DataType } from "@dxos/schema";
182
116
 
183
- // src/session/version-pin.ts
184
- import { Schema as Schema3 } from "effect";
185
- import { getVersion } from "@dxos/echo-db";
186
- import { ObjectId } from "@dxos/echo-schema";
187
- var ObjectVersionSchema = Schema3.Unknown;
188
- var VersionPinSchema = Schema3.Struct({
189
- // TODO(dmaretskyi): Use Ref when those support encoding.
190
- objectId: ObjectId,
191
- // TODO(dmaretskyi): Could be opaque
192
- version: ObjectVersionSchema
193
- });
194
- var VersionPin = class extends VersionPinSchema {
195
- static {
196
- this.DISPOSITION = "version-pin";
197
- }
198
- static fromObject(object) {
199
- return VersionPin.make({
200
- objectId: object.id,
201
- version: getVersion(object)
202
- });
203
- }
204
- static createBlock(pin) {
205
- return {
206
- type: "json",
207
- disposition: VersionPin.DISPOSITION,
208
- json: JSON.stringify(pin)
209
- };
210
- }
117
+ // src/errors.ts
118
+ import { BaseError } from "@dxos/errors";
119
+ var AiAssistantError = class extends BaseError.extend("AI_ASSISTANT_ERROR") {
211
120
  };
212
121
 
213
122
  // src/session/session.ts
214
- function _ts_decorate(decorators, target, key, desc) {
215
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
216
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
217
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
218
- return c > 3 && r && Object.defineProperty(target, key, r), r;
219
- }
220
123
  var __dxlog_file = "/__w/dxos/dxos/packages/core/assistant/src/session/session.ts";
221
- var AISession = class _AISession {
222
- constructor(_options) {
124
+ var AiSession = class {
125
+ constructor(_options = {}) {
223
126
  this._options = _options;
224
- this._parser = new MixedStreamParser();
127
+ this._semaphore = Effect.runSync(Effect.makeSemaphore(1));
225
128
  this._pending = [];
226
129
  this._history = [];
227
- this.message = this._parser.message;
228
- this.block = this._parser.block;
229
- this.update = this._parser.update;
230
- this.streamEvent = this._parser.streamEvent;
130
+ this.message = new Event();
131
+ this.block = new Event();
132
+ this.update = new Event();
133
+ this.streamEvent = new Event();
231
134
  this.userMessage = new Event();
232
135
  this.statusReport = new Event();
233
136
  this.done = new Event();
234
- this.toolStatusReport = new Event();
235
- this._parser.message.on((message) => {
236
- this._pending.push(message);
237
- });
238
- this._parser.block.on((block) => {
239
- if (block.type === "text" && block.disposition === "status") {
240
- this.statusReport.emit(create(AgentStatusReport, {
241
- message: block.text
242
- }));
243
- }
244
- });
245
- }
246
- /**
247
- * Runs the AI model loop interacting with tools and artifacts.
248
- * @param options - The session options.
249
- * @returns The messages generated by the session, including the user's prompt.
250
- */
251
- async run(options) {
252
- const systemTools = [];
253
- switch (this._options.operationModel) {
254
- case "planning":
255
- systemTools.push(this._createQueryArtifactsTool(options.artifacts), this._createPlanningTool(options));
256
- break;
257
- case "importing":
258
- systemTools.push(this._createQueryArtifactsTool(options.artifacts), this._createRequireTool(options.artifacts, (artifactDefinitionIds) => {
259
- for (const artifactDefinitionId of artifactDefinitionIds) {
260
- requiredArtifactIds.add(artifactDefinitionId);
261
- }
262
- }));
263
- break;
264
- case "configured":
265
- break;
266
- default:
267
- throw new TypeError(`Invalid operation model: ${this._options.operationModel}`);
268
- }
269
- this._history = [
270
- ...options.history
271
- ];
272
- this._pending = [
273
- await this._formatUserPrompt(options.artifactDiffResolver, options.prompt, options.history)
274
- ];
275
- this.userMessage.emit(this._pending.at(-1));
276
- this._stream = void 0;
277
- let error;
278
- const requiredArtifactIds = new Set(options.requiredArtifactIds ?? []);
279
- try {
280
- let more = false;
137
+ this.run = (options) => Effect.gen(this, function* () {
138
+ this._history = [
139
+ ...options.history
140
+ ];
141
+ const promptMessages = yield* this._formatUserPrompt(options.prompt, options.history);
142
+ this._pending = [
143
+ promptMessages
144
+ ];
145
+ this.userMessage.emit(promptMessages);
281
146
  do {
282
- const tools = pipe2([
283
- ...systemTools,
284
- ...await Promise.all(options.tools.map((toolId) => options.toolResolver.resolve(toolId))),
285
- ...options.executableTools ?? [],
286
- ...options.artifacts.filter((artifact) => requiredArtifactIds.has(artifact.id)).flatMap((artifact) => artifact.tools)
287
- ], Array3.dedupeWith((a, b) => a.id === b.id));
288
147
  log("request", {
289
148
  pending: this._pending.length,
290
149
  history: this._history.length,
291
- tools: tools.map((tool) => tool.name)
150
+ tools: Object.values(options.toolkit?.tools ?? {}).map((tool) => tool.name)
292
151
  }, {
293
152
  F: __dxlog_file,
294
- L: 231,
153
+ L: 126,
295
154
  S: this,
296
155
  C: (f, a) => f(...a)
297
156
  });
298
- this._stream = await options.client.execStream({
299
- ...options.generationOptions ?? {},
300
- // TODO(burdon): Rename messages or separate history/message.
301
- history: [
302
- ...this._history,
303
- ...this._pending
304
- ],
305
- tools,
306
- systemPrompt: options.systemPrompt ?? createBaseInstructions({
307
- availableArtifacts: [
308
- ...requiredArtifactIds
309
- ],
310
- operationModel: this._options.operationModel
311
- })
312
- });
313
- await this._parser.parse(this._stream);
314
- await this._stream.complete();
315
- log("response", {
316
- pending: this._pending
157
+ const prompt = yield* AiPreprocessor.preprocessAiInput([
158
+ ...this._history,
159
+ ...this._pending
160
+ ]);
161
+ const blueprints = options.blueprints ?? [];
162
+ const systemPrompt = yield* pipe2(blueprints, Effect.forEach((blueprint) => DatabaseService.loadRef(blueprint.instructions)), Effect.flatMap(Effect.forEach((template) => DatabaseService.loadRef(template.source))), Effect.map(Array3.map((template) => `
163
+
164
+ <blueprint>${template.content}</blueprint>`)), Effect.map(Array3.reduce(options.systemPrompt ?? "", String.concat)));
165
+ const blueprintToolkit = yield* ToolResolverService.resolveToolkit(blueprints.flatMap((bp) => bp.tools));
166
+ const blueprintToolkitHandler = yield* blueprintToolkit.toContext(yield* ToolExecutionService.handlersFor(blueprintToolkit));
167
+ const toolkit = options.toolkit != null ? AiToolkit.merge(options.toolkit, blueprintToolkit) : blueprintToolkit;
168
+ const toolkitWithBlueprintHandlers = yield* toolkit.pipe(Effect.provide(blueprintToolkitHandler));
169
+ log.info("run", {
170
+ systemPrompt: [
171
+ systemPrompt.slice(0, 32),
172
+ "...",
173
+ systemPrompt.slice(-32),
174
+ systemPrompt.length
175
+ ].join(" "),
176
+ tools: Object.keys(blueprintToolkit.tools)
317
177
  }, {
318
178
  F: __dxlog_file,
319
- L: 256,
179
+ L: 155,
320
180
  S: this,
321
181
  C: (f, a) => f(...a)
322
182
  });
323
- more = false;
324
- const message = this._pending.at(-1);
325
- invariant(message, void 0, {
326
- F: __dxlog_file,
327
- L: 261,
328
- S: this,
329
- A: [
330
- "message",
331
- ""
332
- ]
333
- });
334
- if (isToolUse(message)) {
335
- log("tool request...", void 0, {
336
- F: __dxlog_file,
337
- L: 263,
338
- S: this,
339
- C: (f, a) => f(...a)
340
- });
341
- const response = await runTools({
342
- message: this._pending.at(-1),
343
- tools,
344
- extensions: options.extensions ?? {},
345
- reportStatus: (status) => this._onToolStatusReport(message, status)
346
- });
347
- log("tool response", {
348
- response
349
- }, {
350
- F: __dxlog_file,
351
- L: 271,
352
- S: this,
353
- C: (f, a) => f(...a)
354
- });
355
- switch (response.type) {
356
- case "continue": {
357
- this._pending = [
358
- ...this._pending,
359
- response.message
360
- ];
361
- this.userMessage.emit(response.message);
362
- more = true;
363
- break;
183
+ const blocks = yield* AiLanguageModel.streamText({
184
+ prompt,
185
+ system: systemPrompt,
186
+ toolkit: toolkitWithBlueprintHandlers,
187
+ disableToolCallResolution: true
188
+ }).pipe(AiParser.parseGptStream({
189
+ onBlock: (block) => Effect.gen(this, function* () {
190
+ if (block.pending) {
191
+ this.update.emit(block);
192
+ } else {
193
+ this.block.emit(block);
364
194
  }
365
- }
366
- }
367
- } while (more);
368
- } catch (err) {
369
- log.catch(err, void 0, {
370
- F: __dxlog_file,
371
- L: 283,
372
- S: this,
373
- C: (f, a) => f(...a)
374
- });
375
- if (err instanceof Error && err.message.includes("Overloaded")) {
376
- error = new AIServiecOverloadedError("AI service overloaded", {
377
- cause: err
378
- });
379
- } else {
380
- error = new Error("AI service error", {
381
- cause: err
382
- });
383
- }
384
- } finally {
385
- this._stream = void 0;
386
- this.done.emit();
387
- }
388
- if (error) {
389
- throw error;
390
- }
391
- return this._pending;
392
- }
393
- async runStructured(schema, options) {
394
- const parser = structuredOutputParser(schema);
395
- const result = await this.run({
396
- ...options,
397
- executableTools: [
398
- ...options.executableTools ?? [],
399
- parser.tool
400
- ]
401
- });
402
- return parser.getResult(result);
403
- }
404
- async _formatUserPrompt(artifactDiffResolver, prompt, history) {
405
- const prelude = [];
406
- if (artifactDiffResolver) {
407
- const versions = gatherObjectVersions(history);
408
- const artifactDiff = await artifactDiffResolver([
409
- ...versions.entries()
410
- ].map(([id, version]) => ({
411
- id,
412
- lastVersion: version
413
- })));
414
- log.info("vision", {
415
- artifactDiff,
416
- versions
417
- }, {
418
- F: __dxlog_file,
419
- L: 327,
420
- S: this,
421
- C: (f, a) => f(...a)
422
- });
423
- for (const [id, { version }] of [
424
- ...artifactDiff.entries()
425
- ]) {
426
- if (ObjectVersion.equals(version, versions.get(id))) {
427
- artifactDiff.delete(id);
428
- continue;
429
- }
430
- prelude.push(VersionPin.createBlock(VersionPin.make({
431
- objectId: id,
432
- version
433
- })));
434
- }
435
- if (artifactDiff.size > 0) {
436
- prelude.push(createArtifactUpdateBlock(artifactDiff));
437
- }
438
- }
439
- return Obj2.make(Message, {
440
- role: "user",
441
- content: [
442
- ...prelude,
443
- {
444
- type: "text",
445
- text: prompt
446
- }
447
- ]
448
- });
449
- }
450
- _createQueryArtifactsTool(artifacts) {
451
- return createTool("system", {
452
- name: "query_artifact_definitions",
453
- description: "Query the available artifact definitions",
454
- schema: Schema4.Struct({}),
455
- execute: async () => {
456
- return ToolResult.Success({
457
- artifactDefinitions: artifacts.map((artifact) => ({
458
- id: artifact.id,
459
- name: artifact.name,
460
- description: artifact.description
461
- }))
462
- });
463
- }
464
- });
465
- }
466
- _createRequireTool(artifacts, onRequire) {
467
- return createTool("system", {
468
- name: "require_artifact_definitions",
469
- description: "Require the use of specific artifact definitions. This will allow the model to interact with artifact definitions and use their tools.",
470
- schema: Schema4.Struct({
471
- artifactDefinitionIds: Schema4.Array(Schema4.String).annotations({
472
- description: "The ids of the artifact definitions to require",
473
- examples: [
474
- [
475
- "artifact:dxos.org/example/Test"
476
- ]
477
- ]
478
- })
479
- }),
480
- execute: async ({ artifactDefinitionIds }) => {
481
- const missingArtifactDefinitionIds = artifactDefinitionIds.filter((artifactId) => !artifacts.some((artifact) => artifact.id === artifactId));
482
- if (missingArtifactDefinitionIds.length > 0) {
483
- return ToolResult.Error(`One or more artifact definition ids are invalid: ${missingArtifactDefinitionIds.join(", ")}`);
484
- }
485
- onRequire(artifactDefinitionIds);
486
- return ToolResult.Success({});
487
- }
488
- });
489
- }
490
- _createPlanningTool(options) {
491
- return createTool("system", {
492
- name: "create_plan",
493
- description: "Create a plan. Make sure that each step is independent and can be executed solely on the data returned by the previous step. The steps only share the data that is specified in the plan.",
494
- schema: Schema4.Struct({
495
- goal: Schema4.String.annotations({
496
- description: "The goal that the plan will achieve."
497
- }),
498
- steps: Schema4.Array(Schema4.Struct({
499
- action: Schema4.String.annotations({
500
- description: "Complete, detailed action to perform."
501
- }),
502
- input: Schema4.String.annotations({
503
- description: "The required input data for this step. First step must not require any data."
504
195
  }),
505
- output: Schema4.String.annotations({
506
- description: "The output data from this step. This is passed to the next step as input."
507
- }),
508
- requiredArtifactIds: Schema4.Array(Schema4.String).annotations({
509
- description: "The ids of the artifacts required to perform this step.",
510
- examples: [
511
- [
512
- "artifact:dxos.org/example/Test"
513
- ]
514
- ]
196
+ onPart: (part) => Effect.gen(this, function* () {
197
+ this.streamEvent.emit(part);
515
198
  })
516
- })).annotations({
517
- description: "Steps"
518
- })
519
- }),
520
- execute: async ({ goal, steps }) => {
521
- const missingArtifactIds = steps.flatMap((step) => step.requiredArtifactIds).filter((artifactId) => !options.artifacts.some((artifact) => artifact.id === artifactId));
522
- if (missingArtifactIds.length > 0) {
523
- return ToolResult.Error(`One or more artifact ids are invalid: ${missingArtifactIds.join(", ")}`);
199
+ }), Stream.runCollect, Effect.map(Chunk.toArray));
200
+ const response = Obj2.make(DataType.Message, {
201
+ created: (/* @__PURE__ */ new Date()).toISOString(),
202
+ sender: {
203
+ role: "assistant"
204
+ },
205
+ blocks
206
+ });
207
+ this._pending.push(response);
208
+ this.message.emit(response);
209
+ const toolCalls = getToolCalls(response);
210
+ if (toolCalls.length === 0) {
211
+ break;
524
212
  }
525
- const stepResults = [];
526
- for (const step of steps) {
527
- log("executing step", {
528
- action: step.action
529
- }, {
530
- F: __dxlog_file,
531
- L: 434,
532
- S: this,
533
- C: (f, a) => f(...a)
534
- });
535
- const session = new _AISession({
536
- operationModel: "importing"
537
- });
538
- session.message.on((ev) => this.message.emit(ev));
539
- session.block.on((ev) => this.block.emit(ev));
540
- session.update.on((ev) => this.update.emit(ev));
541
- session.streamEvent.on((ev) => this.streamEvent.emit(ev));
542
- session.userMessage.on((ev) => this.userMessage.emit(ev));
543
- const messages = await session.run({
544
- artifacts: options.artifacts,
545
- tools: options.tools,
546
- history: options.history,
547
- extensions: options.extensions,
548
- requiredArtifactIds: step.requiredArtifactIds.slice(),
549
- prompt: `
550
- You are an agent that executes the subtask in a plan.
551
-
552
- While you know the plan's goal only focus on your subtask
553
- Use the data from the previous step to complete your task.
554
- Return all of the data from "output" in your last message.
555
-
556
- Current step (that you need to complete):
557
- ${JSON.stringify({
558
- goal,
559
- input: step.input,
560
- output: step.output,
561
- yourTask: step.action
562
- }, null, 2)}
563
-
564
- Previous step results:
565
- ${JSON.stringify(stepResults.at(-1))}.
566
- `,
567
- generationOptions: options.generationOptions,
568
- client: options.client,
569
- toolResolver: options.toolResolver,
570
- artifactDiffResolver: options.artifactDiffResolver
213
+ const toolResults = yield* runTools(toolCalls, toolkitWithBlueprintHandlers);
214
+ this._pending.push(Obj2.make(DataType.Message, {
215
+ created: (/* @__PURE__ */ new Date()).toISOString(),
216
+ sender: {
217
+ role: "user"
218
+ },
219
+ blocks: toolResults
220
+ }));
221
+ } while (true);
222
+ return this._pending;
223
+ }).pipe(this._semaphore.withPermits(1), Effect.withSpan("AiSession.run"));
224
+ this._formatUserPrompt = (prompt, history) => Effect.gen(function* () {
225
+ const prelude = [];
226
+ const artifactDiffResolver = yield* Effect.serviceOption(ArtifactDiffResolver);
227
+ if (Option.isSome(artifactDiffResolver)) {
228
+ const versions = gatherObjectVersions(history);
229
+ const artifactDiff = yield* Effect.tryPromise({
230
+ try: () => artifactDiffResolver.value.resolve([
231
+ ...versions.entries()
232
+ ].map(([id, version]) => ({
233
+ id,
234
+ lastVersion: version
235
+ }))),
236
+ catch: AiAssistantError.wrap("Artifact diff resolution error")
237
+ });
238
+ log.info("vision", {
239
+ artifactDiff,
240
+ versions
241
+ }, {
242
+ F: __dxlog_file,
243
+ L: 240,
244
+ S: this,
245
+ C: (f, a) => f(...a)
246
+ });
247
+ for (const [id, { version }] of [
248
+ ...artifactDiff.entries()
249
+ ]) {
250
+ if (ObjectVersion.equals(version, versions.get(id))) {
251
+ artifactDiff.delete(id);
252
+ continue;
253
+ }
254
+ prelude.push({
255
+ _tag: "anchor",
256
+ objectId: id,
257
+ version
571
258
  });
572
- const result = messages.at(-1);
573
- stepResults.push(result);
574
259
  }
575
- return ToolResult.Success({
576
- stepResults
577
- });
260
+ if (artifactDiff.size > 0) {
261
+ prelude.push(createArtifactUpdateBlock(artifactDiff));
262
+ }
578
263
  }
264
+ return Obj2.make(DataType.Message, {
265
+ created: (/* @__PURE__ */ new Date()).toISOString(),
266
+ sender: {
267
+ role: "user"
268
+ },
269
+ blocks: [
270
+ ...prelude,
271
+ {
272
+ _tag: "text",
273
+ text: prompt
274
+ }
275
+ ]
276
+ });
579
277
  });
580
278
  }
581
- _onToolStatusReport(message, status) {
582
- this.toolStatusReport.emit({
583
- message,
584
- status
585
- });
279
+ async runStructured(schema, options) {
280
+ return todo();
586
281
  }
587
282
  abort() {
588
283
  this._stream?.abort();
589
284
  }
590
285
  };
591
- _ts_decorate([
592
- synchronized
593
- ], AISession.prototype, "run", null);
594
- var createBaseInstructions = ({ availableArtifacts, operationModel }) => `
595
- You are a friendly, advanced AI assistant capable of creating and managing artifacts from available data and tools.
596
- Your task is to process user commands and questions and decide how best to respond.
597
- In some cases, you will need to create or reference data objects called artifacts.
598
-
599
- Follow these guidelines carefully:
600
-
601
- Decision-making:
602
-
603
- - Analyze the structure and type of the content in the user's message.
604
-
605
-
606
- ${operationModel === "planning" ? `
607
- - Can you complete the task using the available artifacts?
608
- - If you can't complete the task using the available artifacts, query the list of available artifacts using the appropriate tool.
609
- - Identify which artifacts are relevant to the user's request.
610
- - Break down the user's request into a step-by-step plan that you will use to execute the user's request, the plan items should include artifacts which will be used to perform the actions.
611
- ` : ""}
612
- ${operationModel === "importing" ? `
613
- - Can you complete the task using the available artifacts?
614
- - If you can't complete the task using the available artifacts, query the list of available artifacts using the appropriate tool.
615
- - Identify which artifacts are relevant to the user's request.
616
- - Are the required artifacts already available?
617
- - If not, select which artifact(s) will be the most relevant and require them using the require_artifacts tool.
618
- - The require'd artifact tools will be available for use after require.
619
- ` : ""}
620
- ${operationModel === "configured" ? `
621
- - Select the most relevant artifact(s) to complete the task.
622
- - Call the appropriate tool to use the artifact(s).
623
- ` : ""}
624
-
625
- ${availableArtifacts.length > 0 ? `Artifacts already in context: ${availableArtifacts.join("\n")}` : ""}
626
- `;
627
- var AIServiecOverloadedError = class extends Schema4.TaggedError()("AIServiecOverloadedError", {}) {
628
- };
629
286
  var gatherObjectVersions = (messages) => {
630
287
  const artifactIds = /* @__PURE__ */ new Map();
631
288
  for (const message of messages) {
632
- for (const block of message.content) {
633
- if (block.type === "json" && block.disposition === VersionPin.DISPOSITION) {
634
- const pin = VersionPin.pipe(Schema4.decodeOption)(JSON.parse(block.json)).pipe(Option.getOrUndefined);
635
- if (!pin) {
636
- continue;
637
- }
638
- artifactIds.set(pin.objectId, pin.version);
289
+ for (const block of message.blocks) {
290
+ if (block._tag === "anchor") {
291
+ artifactIds.set(block.objectId, block.version);
639
292
  }
640
293
  }
641
294
  }
@@ -643,7 +296,8 @@ var gatherObjectVersions = (messages) => {
643
296
  };
644
297
  var createArtifactUpdateBlock = (artifactDiff) => {
645
298
  return {
646
- type: "text",
299
+ _tag: "text",
300
+ // TODO(dmaretskyi): Does this need to be a special content-block?
647
301
  disposition: "artifact-update",
648
302
  text: `
649
303
  The following artifacts have been updated since the last message:
@@ -654,9 +308,44 @@ ${diff}` : ""}</changed-artifact>`).join("\n")}
654
308
  `
655
309
  };
656
310
  };
311
+ var ArtifactDiffResolver = class extends Context.Tag("ArtifactDiffResolver")() {
312
+ };
313
+ var runTools = Effect.fn("runTools")(function* (toolCalls, toolkit) {
314
+ const toolkitWithHandlers = Effect.isEffect(toolkit) ? yield* toolkit : toolkit;
315
+ return yield* Effect.forEach(toolCalls, (toolCall) => runTool(toolkitWithHandlers, toolCall));
316
+ });
317
+
318
+ // src/session/version-pin.ts
319
+ import { Schema as Schema2 } from "effect";
320
+ import { getVersion } from "@dxos/echo-db";
321
+ import { ObjectId } from "@dxos/echo-schema";
322
+ var ObjectVersionSchema = Schema2.Unknown;
323
+ var VersionPinSchema = Schema2.Struct({
324
+ // TODO(dmaretskyi): Use Ref when those support encoding.
325
+ objectId: ObjectId,
326
+ // TODO(dmaretskyi): Could be opaque
327
+ version: ObjectVersionSchema
328
+ });
329
+ var VersionPin = class extends VersionPinSchema {
330
+ static {
331
+ this.DISPOSITION = "version-pin";
332
+ }
333
+ static fromObject(object) {
334
+ return VersionPin.make({
335
+ objectId: object.id,
336
+ version: getVersion(object)
337
+ });
338
+ }
339
+ static createBlock(pin) {
340
+ return {
341
+ _tag: "json",
342
+ disposition: VersionPin.DISPOSITION,
343
+ data: JSON.stringify(pin)
344
+ };
345
+ }
346
+ };
657
347
 
658
348
  // src/conversation/conversation.ts
659
- var __dxlog_file2 = "/__w/dxos/dxos/packages/core/assistant/src/conversation/conversation.ts";
660
349
  var Conversation = class {
661
350
  constructor(options) {
662
351
  /**
@@ -664,72 +353,51 @@ var Conversation = class {
664
353
  * This is called before the first message is sent.
665
354
  */
666
355
  this.onBegin = new Event2();
667
- this._serviceContainer = options.serviceContainer;
356
+ this.run = (options) => Effect2.gen(this, function* () {
357
+ const session = new AiSession();
358
+ this.onBegin.emit(session);
359
+ const history = yield* Effect2.promise(() => this.getHistory());
360
+ const context = yield* Effect2.promise(() => this.context.query());
361
+ const blueprints = yield* Effect2.forEach(context.blueprints.values(), DatabaseService2.loadRef);
362
+ const contextObjects = yield* Effect2.forEach(context.objects.values(), DatabaseService2.loadRef);
363
+ const systemPrompt = (options.systemPrompt ?? "") + "\n\n" + contextObjects.map((obj) => `<object>${Obj3.getDXN(obj)}</object>`).join("\n");
364
+ const messages = yield* session.run({
365
+ prompt: options.prompt,
366
+ history,
367
+ systemPrompt,
368
+ toolkit: options.toolkit,
369
+ blueprints
370
+ });
371
+ yield* Effect2.promise(() => this._queue.append(messages));
372
+ return messages;
373
+ }).pipe(Effect2.withSpan("Conversation.run"));
668
374
  this._queue = options.queue;
669
375
  this.context = new ContextBinder(this._queue);
670
376
  }
671
- async run(options) {
672
- const session = new AISession({
673
- operationModel: "configured"
674
- });
675
- this.onBegin.emit(session);
676
- const history = await this.getHistory();
677
- const context = await this.context.query();
678
- const blueprints = (await Ref.Array.loadAll([
679
- ...context.blueprints
680
- ])).filter(isNonNullable);
681
- if (blueprints.length > 1) {
682
- log2.warn("multiple blueprints are not yet supported", void 0, {
683
- F: __dxlog_file2,
684
- L: 72,
685
- S: this,
686
- C: (f, a) => f(...a)
687
- });
688
- }
689
- const messages = await session.run({
690
- history,
691
- prompt: options.prompt,
692
- systemPrompt: (options.systemPrompt ?? "") + (blueprints.at(0)?.instructions ?? ""),
693
- // TODO(dmaretskyi): Artifacts come from the blueprint?
694
- artifacts: options.artifacts ?? [],
695
- tools: blueprints.at(0)?.tools ?? [],
696
- executableTools: options.tools,
697
- requiredArtifactIds: options.requiredArtifactIds,
698
- client: this._serviceContainer.getService(AiService).client,
699
- toolResolver: this._serviceContainer.getService(ToolResolverService).toolResolver,
700
- extensions: {
701
- serviceContainer: this._serviceContainer,
702
- ...options.extensions
703
- },
704
- generationOptions: options.generationOptions
705
- });
706
- await this._queue.append(messages);
707
- return messages;
708
- }
709
377
  async getHistory() {
710
378
  const queueItems = await this._queue.queryObjects();
711
- return queueItems.filter(Obj3.instanceOf(Message2));
379
+ return queueItems.filter(Obj3.instanceOf(DataType2.Message));
712
380
  }
713
381
  };
714
382
 
715
383
  // src/extraction/extraction.ts
716
- import { Schema as Schema5 } from "effect";
384
+ import { Schema as Schema3 } from "effect";
717
385
  import { asyncTimeout } from "@dxos/async";
718
386
  import { Expando } from "@dxos/echo-schema";
719
- import { log as log3 } from "@dxos/log";
720
- import { DataType } from "@dxos/schema";
721
- var __dxlog_file3 = "/__w/dxos/dxos/packages/core/assistant/src/extraction/extraction.ts";
722
- var ExtractionInput = Schema5.Struct({
723
- message: DataType.Message,
724
- objects: Schema5.optional(Schema5.Array(Expando)),
725
- options: Schema5.optional(Schema5.Struct({
726
- timeout: Schema5.optional(Schema5.Number),
727
- fallbackToRaw: Schema5.optional(Schema5.Boolean)
387
+ import { log as log2 } from "@dxos/log";
388
+ import { DataType as DataType3 } from "@dxos/schema";
389
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/core/assistant/src/extraction/extraction.ts";
390
+ var ExtractionInput = Schema3.Struct({
391
+ message: DataType3.Message,
392
+ objects: Schema3.optional(Schema3.Array(Expando)),
393
+ options: Schema3.optional(Schema3.Struct({
394
+ timeout: Schema3.optional(Schema3.Number),
395
+ fallbackToRaw: Schema3.optional(Schema3.Boolean)
728
396
  }))
729
397
  });
730
- var ExtractionOutput = Schema5.Struct({
731
- message: DataType.Message,
732
- timeElapsed: Schema5.Number
398
+ var ExtractionOutput = Schema3.Struct({
399
+ message: DataType3.Message,
400
+ timeElapsed: Schema3.Number
733
401
  });
734
402
  var processTranscriptMessage = async (params) => {
735
403
  try {
@@ -740,10 +408,10 @@ var processTranscriptMessage = async (params) => {
740
408
  }
741
409
  } catch (error) {
742
410
  if (params.options?.fallbackToRaw) {
743
- log3.warn("failed to process message, falling back to raw text", {
411
+ log2.warn("failed to process message, falling back to raw text", {
744
412
  error
745
413
  }, {
746
- F: __dxlog_file3,
414
+ F: __dxlog_file2,
747
415
  L: 66,
748
416
  S: void 0,
749
417
  C: (f, a) => f(...a)
@@ -759,27 +427,27 @@ var processTranscriptMessage = async (params) => {
759
427
  };
760
428
 
761
429
  // src/extraction/extraction-llm-function/extraction-llm-function.ts
762
- import { Message as Message3, ToolRegistry } from "@dxos/ai";
430
+ import { ToolRegistry, AiService } from "@dxos/ai";
763
431
  import { Obj as Obj4 } from "@dxos/echo";
764
- import { create as create2 } from "@dxos/echo-schema";
765
- import { AiService as AiService2, defineFunction } from "@dxos/functions";
766
- import { DataType as DataType2 } from "@dxos/schema";
432
+ import { create } from "@dxos/echo-schema";
433
+ import { defineFunction } from "@dxos/functions";
434
+ import { DataType as DataType4 } from "@dxos/schema";
767
435
 
768
436
  // raw-loader:./instructions.tpl?raw
769
437
  var instructions_default = 'You are an AI assistant specialized in processing and enhancing transcripts with contextual information.\nYour task is to analyze a given transcript and extract references to the context objects.\n\nThe context and transcript are provided in the user message in `context` and `transcript` XML tags.\n\nHere are your instructions:\n\n1. Read the transcript and context information provided above.\n\n2. Process each segment of the transcript separately.\n\n3. For each segment:\n a. Analyze the content and identify relevant information from the context.\n b. Extract a number of references to the context objects that are mentioned in the segment.\n c. Output the references in the format `{ "quote": "earnings report", "id": "01JT0JP9AX0XKGZX4MV4B69VT6" }`.\n d. If there are no references, just output an empty array.\n\n4. Maintain the exact order and structure of the original transcript segments.\n\nOutput Format:\nYou have been provided with a tool that specifies output format\n\nRemember:\n- Only quote the text that is in the transcript.\n- Analyze each segment carefully before processing it.\n- Only reference objects that appear in the context and exactly by their id, If the object is not in the context, do not insert a reference. \n\nNow, process the transcript and context provided below according to these instructions.';
770
438
 
771
439
  // src/extraction/quotes.ts
772
- import { Schema as Schema6 } from "effect";
440
+ import { Schema as Schema4 } from "effect";
773
441
  import { Query, Filter } from "@dxos/echo";
774
442
  import { ObjectId as ObjectId2 } from "@dxos/echo-schema";
775
443
  import { DXN } from "@dxos/keys";
776
- import { log as log4 } from "@dxos/log";
777
- var __dxlog_file4 = "/__w/dxos/dxos/packages/core/assistant/src/extraction/quotes.ts";
778
- var ReferencedQuotes = Schema6.Struct({
779
- references: Schema6.Array(Schema6.Struct({
780
- id: Schema6.String,
781
- quote: Schema6.String
782
- })).pipe(Schema6.mutable).annotations({
444
+ import { log as log3 } from "@dxos/log";
445
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/core/assistant/src/extraction/quotes.ts";
446
+ var ReferencedQuotes = Schema4.Struct({
447
+ references: Schema4.Array(Schema4.Struct({
448
+ id: Schema4.String,
449
+ quote: Schema4.String
450
+ })).pipe(Schema4.mutable).annotations({
783
451
  // TODO(burdon): Does this description make sense?
784
452
  description: `
785
453
  The references to the context objects that are mentioned in the transcript.
@@ -792,11 +460,11 @@ var findQuotes = async (quotes, db) => {
792
460
  const { objects } = await db.query(Query.select(Filter.text(quote, {
793
461
  type: "vector"
794
462
  }))).run();
795
- log4.info("found quotes in vector index", {
463
+ log3.info("found quotes in vector index", {
796
464
  objects,
797
465
  quote
798
466
  }, {
799
- F: __dxlog_file4,
467
+ F: __dxlog_file3,
800
468
  L: 35,
801
469
  S: void 0,
802
470
  C: (f, a) => f(...a)
@@ -830,8 +498,8 @@ var extractionAnthropicFn = defineFunction({
830
498
  outputSchema: ExtractionOutput,
831
499
  handler: async ({ data: { message, objects }, context }) => {
832
500
  const startTime = performance.now();
833
- const ai = context.getService(AiService2);
834
- const session = new AISession({
501
+ const ai = context.getService(AiService);
502
+ const session = new AiSession({
835
503
  operationModel: "configured"
836
504
  });
837
505
  const result = await session.runStructured(ReferencedQuotes, {
@@ -841,15 +509,18 @@ var extractionAnthropicFn = defineFunction({
841
509
  client: ai.client,
842
510
  systemPrompt: instructions_default,
843
511
  history: [
844
- Obj4.make(Message3, {
845
- role: "user",
846
- content: [
512
+ Obj4.make(DataType4.Message, {
513
+ created: (/* @__PURE__ */ new Date()).toISOString(),
514
+ sender: {
515
+ role: "user"
516
+ },
517
+ blocks: [
847
518
  {
848
- type: "text",
519
+ _tag: "text",
849
520
  text: `<context>${JSON.stringify(objects)}</context>`
850
521
  },
851
522
  {
852
- type: "text",
523
+ _tag: "text",
853
524
  text: `<transcript>${JSON.stringify(message.blocks)}</transcript>`
854
525
  }
855
526
  ]
@@ -861,9 +532,9 @@ var extractionAnthropicFn = defineFunction({
861
532
  toolResolver: new ToolRegistry([])
862
533
  });
863
534
  return {
864
- message: create2(DataType2.Message, {
535
+ message: create(DataType4.Message, {
865
536
  ...message,
866
- blocks: message.blocks.map((block, i) => block.type !== "transcription" ? block : {
537
+ blocks: message.blocks.map((block, i) => block._tag !== "transcript" ? block : {
867
538
  ...block,
868
539
  text: insertReferences(block.text, result)
869
540
  })
@@ -875,22 +546,22 @@ var extractionAnthropicFn = defineFunction({
875
546
 
876
547
  // src/extraction/extraction-ner-function/extraction-ner-function.ts
877
548
  import { asyncTimeout as asyncTimeout2 } from "@dxos/async";
878
- import { create as create3 } from "@dxos/echo-schema";
879
- import { DatabaseService, defineFunction as defineFunction2 } from "@dxos/functions";
880
- import { invariant as invariant2 } from "@dxos/invariant";
881
- import { log as log6 } from "@dxos/log";
882
- import { DataType as DataType3 } from "@dxos/schema";
549
+ import { create as create2 } from "@dxos/echo-schema";
550
+ import { DatabaseService as DatabaseService3, defineFunction as defineFunction2 } from "@dxos/functions";
551
+ import { invariant } from "@dxos/invariant";
552
+ import { log as log5 } from "@dxos/log";
553
+ import { DataType as DataType5 } from "@dxos/schema";
883
554
 
884
555
  // src/extraction/extraction-ner-function/named-entity-recognition.ts
885
556
  import { pipeline } from "@xenova/transformers";
886
- import { log as log5 } from "@dxos/log";
887
- var __dxlog_file5 = "/__w/dxos/dxos/packages/core/assistant/src/extraction/extraction-ner-function/named-entity-recognition.ts";
557
+ import { log as log4 } from "@dxos/log";
558
+ var __dxlog_file4 = "/__w/dxos/dxos/packages/core/assistant/src/extraction/extraction-ner-function/named-entity-recognition.ts";
888
559
  var _ner;
889
560
  var getNer = () => {
890
561
  if (!_ner) {
891
562
  _ner = pipeline("ner", "Xenova/bert-base-NER").then((ner) => {
892
- log5.info("NER model is ready", void 0, {
893
- F: __dxlog_file5,
563
+ log4.info("NER model is ready", void 0, {
564
+ F: __dxlog_file4,
894
565
  L: 23,
895
566
  S: void 0,
896
567
  C: (f, a) => f(...a)
@@ -964,69 +635,69 @@ var combineNerTokens = (group) => {
964
635
  };
965
636
 
966
637
  // src/extraction/extraction-ner-function/extraction-ner-function.ts
967
- var __dxlog_file6 = "/__w/dxos/dxos/packages/core/assistant/src/extraction/extraction-ner-function/extraction-ner-function.ts";
638
+ var __dxlog_file5 = "/__w/dxos/dxos/packages/core/assistant/src/extraction/extraction-ner-function/extraction-ner-function.ts";
968
639
  var extractionNerFn = defineFunction2({
969
640
  description: "Extracts named entities from a text",
970
641
  inputSchema: ExtractionInput,
971
642
  outputSchema: ExtractionOutput,
972
643
  handler: async ({ data: { message, options }, context }) => {
973
- log6.info("input", {
644
+ log5.info("input", {
974
645
  message,
975
646
  options
976
647
  }, {
977
- F: __dxlog_file6,
978
- L: 22,
648
+ F: __dxlog_file5,
649
+ L: 25,
979
650
  S: void 0,
980
651
  C: (f, a) => f(...a)
981
652
  });
982
653
  const startTime = performance.now();
983
- const { db } = context.getService(DatabaseService);
654
+ const { db } = context.getService(DatabaseService3);
984
655
  const entitiesPromise = Promise.all(message.blocks.map(async (block) => {
985
- invariant2(block.type === "transcription" || block.type === "text", "Block must have text", {
986
- F: __dxlog_file6,
987
- L: 28,
656
+ invariant(block._tag === "transcript" || block._tag === "text", "Block must have text", {
657
+ F: __dxlog_file5,
658
+ L: 31,
988
659
  S: void 0,
989
660
  A: [
990
- "block.type === 'transcription' || block.type === 'text'",
661
+ "block._tag === 'transcript' || block._tag === 'text'",
991
662
  "'Block must have text'"
992
663
  ]
993
664
  });
994
665
  return extractFullEntities(block.text);
995
666
  })).then((entities2) => entities2.flat());
996
667
  const entities = options?.timeout ? await asyncTimeout2(entitiesPromise, options.timeout) : await entitiesPromise;
997
- log6.info("entities", {
668
+ log5.info("entities", {
998
669
  entities
999
670
  }, {
1000
- F: __dxlog_file6,
1001
- L: 33,
671
+ F: __dxlog_file5,
672
+ L: 36,
1002
673
  S: void 0,
1003
674
  C: (f, a) => f(...a)
1004
675
  });
1005
676
  const quoteReferences = await findQuotes(entities.map((entity) => entity.word), db);
1006
677
  const blocksWithReferences = message.blocks.map((block, i) => {
1007
- invariant2(block.type === "transcription" || block.type === "text", "Block must have text", {
1008
- F: __dxlog_file6,
1009
- L: 39,
678
+ invariant(block._tag === "transcript" || block._tag === "text", "Block must have text", {
679
+ F: __dxlog_file5,
680
+ L: 42,
1010
681
  S: void 0,
1011
682
  A: [
1012
- "block.type === 'transcription' || block.type === 'text'",
683
+ "block._tag === 'transcript' || block._tag === 'text'",
1013
684
  "'Block must have text'"
1014
685
  ]
1015
686
  });
1016
687
  return {
1017
688
  ...block,
1018
- text: insertReferences(block.text, quoteReferences)
689
+ text: insertReferences(block._tag, quoteReferences)
1019
690
  };
1020
691
  });
1021
- const messageWithReferences = create3(DataType3.Message, {
692
+ const messageWithReferences = create2(DataType5.Message, {
1022
693
  ...message,
1023
694
  blocks: blocksWithReferences
1024
695
  });
1025
- log6.info("output", {
696
+ log5.info("output", {
1026
697
  messageWithReferences
1027
698
  }, {
1028
- F: __dxlog_file6,
1029
- L: 47,
699
+ F: __dxlog_file5,
700
+ L: 50,
1030
701
  S: void 0,
1031
702
  C: (f, a) => f(...a)
1032
703
  });
@@ -1037,11 +708,127 @@ var extractionNerFn = defineFunction2({
1037
708
  }
1038
709
  });
1039
710
 
711
+ // src/functions/services.ts
712
+ import { AiTool } from "@effect/ai";
713
+ import { Context as Context2, Effect as Effect3, Layer, Match, Predicate, Record, Schema as Schema5 } from "effect";
714
+ import { AiToolNotFoundError, ToolExecutionService as ToolExecutionService2, ToolResolverService as ToolResolverService2 } from "@dxos/ai";
715
+ import { todo as todo2 } from "@dxos/debug";
716
+ import { FunctionError } from "@dxos/functions";
717
+ import { invariant as invariant2 } from "@dxos/invariant";
718
+ var __dxlog_file6 = "/__w/dxos/dxos/packages/core/assistant/src/functions/services.ts";
719
+ var makeToolResolverFromFunctions = (functions) => {
720
+ return Layer.succeed(ToolResolverService2, {
721
+ resolve: Effect3.fn("resolveTool")(function* (id) {
722
+ const fn = functions.find((f) => f.name === id);
723
+ if (!fn) {
724
+ return yield* Effect3.fail(new AiToolNotFoundError(id));
725
+ }
726
+ return projectFunctionToTool(fn);
727
+ })
728
+ });
729
+ };
730
+ var makeToolExecutionServiceFromFunctions = (functions) => {
731
+ return Layer.succeed(ToolExecutionService2, {
732
+ handlersFor: (toolkit) => {
733
+ const makeHandler = (tool) => {
734
+ return Effect3.fn("toolFunctionHandler")(function* (input) {
735
+ const { functionName } = Context2.get(FunctionToolAnnotation)(tool.annotations);
736
+ const fnDef = functions.find((f) => f.name === functionName);
737
+ if (!fnDef) {
738
+ return yield* Effect3.fail(new AiToolNotFoundError(tool.name));
739
+ }
740
+ return yield* invokeFunction(fnDef, input).pipe(Effect3.catchAllDefect((defect) => Effect3.fail(defect)));
741
+ });
742
+ };
743
+ return toolkit.of(Record.map(toolkit.tools, (tool, name) => makeHandler(tool)));
744
+ }
745
+ });
746
+ };
747
+ var FunctionToolAnnotation = class extends Context2.Tag("@dxos/assisatnt/FunctionToolAnnotation")() {
748
+ };
749
+ var toolCache = /* @__PURE__ */ new WeakMap();
750
+ var projectFunctionToTool = (fn) => {
751
+ if (toolCache.has(fn)) {
752
+ return toolCache.get(fn);
753
+ }
754
+ const tool = AiTool.make(makeToolName(fn.name), {
755
+ description: fn.description,
756
+ parameters: createStructFieldsFromSchema(fn.inputSchema),
757
+ // TODO(dmaretskyi): Include output schema.
758
+ failure: Schema5.Any
759
+ }).annotate(FunctionToolAnnotation, {
760
+ functionName: fn.name
761
+ });
762
+ toolCache.set(fn, tool);
763
+ return tool;
764
+ };
765
+ var makeToolName = (name) => {
766
+ const toolName = name.replace(/[^a-zA-Z0-9]/g, "");
767
+ invariant2(toolName.match(/^[a-zA-Z_][a-zA-Z0-9-_]*$/), void 0, {
768
+ F: __dxlog_file6,
769
+ L: 80,
770
+ S: void 0,
771
+ A: [
772
+ "toolName.match(/^[a-zA-Z_][a-zA-Z0-9-_]*$/)",
773
+ ""
774
+ ]
775
+ });
776
+ return toolName;
777
+ };
778
+ var createStructFieldsFromSchema = (schema) => {
779
+ return Match.value(schema.ast).pipe(Match.when(Predicate.isTagged("TypeLiteral"), (ast) => {
780
+ return Object.fromEntries(ast.propertySignatures.map((prop) => [
781
+ prop.name,
782
+ Schema5.make(prop.type)
783
+ ]));
784
+ }), Match.orElseAbsurd);
785
+ };
786
+ var invokeFunction = (fnDef, input) => Effect3.gen(function* () {
787
+ const assertInput = fnDef.inputSchema.pipe(Schema5.asserts);
788
+ assertInput(input);
789
+ const context = {
790
+ getService: () => todo2(),
791
+ getSpace: async (_spaceId) => {
792
+ throw new Error("Not available. Use the database service instead.");
793
+ },
794
+ space: void 0,
795
+ get ai() {
796
+ throw new Error("Not available. Use the ai service instead.");
797
+ }
798
+ };
799
+ const data = yield* Effect3.gen(function* () {
800
+ const result = fnDef.handler({
801
+ context,
802
+ data: input
803
+ });
804
+ if (Effect3.isEffect(result)) {
805
+ return yield* result.pipe(Effect3.orDie);
806
+ } else if (typeof result === "object" && result !== null && "then" in result && typeof result.then === "function") {
807
+ return yield* Effect3.promise(() => result);
808
+ } else {
809
+ return result;
810
+ }
811
+ }).pipe(Effect3.orDie, Effect3.catchAllDefect((defect) => Effect3.die(new FunctionError("Error running function", {
812
+ context: {
813
+ name: fnDef.name
814
+ },
815
+ cause: defect
816
+ }))));
817
+ const assertOutput = fnDef.outputSchema?.pipe(Schema5.asserts);
818
+ assertOutput(data);
819
+ return data;
820
+ }).pipe(Effect3.withSpan("invokeFunction", {
821
+ attributes: {
822
+ name: fnDef.name
823
+ }
824
+ }));
825
+
1040
826
  // src/research/exa.ts
1041
- import { Schema as Schema7 } from "effect";
827
+ import { AiTool as AiTool2, AiToolkit as AiToolkit2 } from "@effect/ai";
828
+ import { Effect as Effect4, Schema as Schema6 } from "effect";
1042
829
  import Exa from "exa-js";
1043
- import { createTool as createTool2, ToolResult as ToolResult2 } from "@dxos/ai";
1044
- import { log as log7 } from "@dxos/log";
830
+ import { CredentialsService } from "@dxos/functions";
831
+ import { log as log6 } from "@dxos/log";
1045
832
 
1046
833
  // src/testing/exa-search-1748337321991.ts
1047
834
  var exa_search_1748337321991_default = {
@@ -1554,64 +1341,60 @@ var SEARCH_RESULTS = [
1554
1341
 
1555
1342
  // src/research/exa.ts
1556
1343
  var __dxlog_file7 = "/__w/dxos/dxos/packages/core/assistant/src/research/exa.ts";
1557
- var createExaTool = ({ apiKey }) => {
1558
- const exa = new Exa(apiKey);
1559
- return createTool2("search", {
1560
- name: "web_search",
1561
- description: "Search the web for information",
1562
- schema: Schema7.Struct({
1563
- query: Schema7.String.annotations({
1564
- description: "The query to search for"
1565
- })
1566
- }),
1567
- execute: async ({ query }) => {
1568
- const context = await exa.searchAndContents(query, {
1569
- type: "auto",
1570
- text: {
1571
- maxCharacters: 3e3
1572
- },
1573
- livecrawl: "always"
1574
- });
1575
- log7.info("exa search", {
1576
- query,
1577
- costDollars: context.costDollars
1578
- }, {
1579
- F: __dxlog_file7,
1580
- L: 35,
1581
- S: void 0,
1582
- C: (f, a) => f(...a)
1583
- });
1584
- return ToolResult2.Success(context);
1585
- }
1586
- });
1587
- };
1588
- var createMockExaTool = () => {
1589
- return createTool2("search", {
1590
- name: "web_search",
1591
- description: "Search the web for information",
1592
- schema: Schema7.Struct({
1593
- query: Schema7.String.annotations({
1594
- description: "The query to search for"
1595
- })
1596
- }),
1597
- execute: async ({ query }) => {
1598
- const result = SEARCH_RESULTS.reduce((closest, current) => {
1599
- if (!current.autopromptString) {
1600
- return closest;
1601
- }
1602
- if (!closest) {
1603
- return current;
1604
- }
1605
- const dist1 = levenshteinDistance(query, current.autopromptString);
1606
- const dist2 = levenshteinDistance(query, closest.autopromptString || "");
1607
- const weight1 = dist1 / Math.max(query.length, current.autopromptString.length);
1608
- const weight2 = dist2 / Math.max(query.length, closest.autopromptString?.length || 0);
1609
- return weight1 < weight2 ? current : closest;
1610
- }, null);
1611
- return ToolResult2.Success(result);
1612
- }
1613
- });
1344
+ var ExaToolkit = class extends AiToolkit2.make(AiTool2.make("exa_search", {
1345
+ description: "Search the web for information",
1346
+ parameters: {
1347
+ query: Schema6.String.annotations({
1348
+ description: "The query to search for"
1349
+ })
1350
+ },
1351
+ success: Schema6.Unknown,
1352
+ failure: Schema6.Never
1353
+ }).addRequirement()) {
1614
1354
  };
1355
+ var LiveExaHandler = ExaToolkit.toLayer({
1356
+ exa_search: Effect4.fn(function* ({ query }) {
1357
+ const credential = yield* CredentialsService.getCredential({
1358
+ service: "exa.ai"
1359
+ });
1360
+ const exa = new Exa(credential.apiKey);
1361
+ const context = yield* Effect4.promise(async () => exa.searchAndContents(query, {
1362
+ type: "auto",
1363
+ text: {
1364
+ maxCharacters: 3e3
1365
+ },
1366
+ livecrawl: "always"
1367
+ }));
1368
+ log6.info("exa search", {
1369
+ query,
1370
+ costDollars: context.costDollars
1371
+ }, {
1372
+ F: __dxlog_file7,
1373
+ L: 40,
1374
+ S: this,
1375
+ C: (f, a) => f(...a)
1376
+ });
1377
+ return context;
1378
+ })
1379
+ });
1380
+ var MockExaHandler = ExaToolkit.toLayer({
1381
+ exa_search: Effect4.fn(function* ({ query }) {
1382
+ const result = SEARCH_RESULTS.reduce((closest, current) => {
1383
+ if (!current.autopromptString) {
1384
+ return closest;
1385
+ }
1386
+ if (!closest) {
1387
+ return current;
1388
+ }
1389
+ const dist1 = levenshteinDistance(query, current.autopromptString);
1390
+ const dist2 = levenshteinDistance(query, closest.autopromptString || "");
1391
+ const weight1 = dist1 / Math.max(query.length, current.autopromptString.length);
1392
+ const weight2 = dist2 / Math.max(query.length, closest.autopromptString?.length || 0);
1393
+ return weight1 < weight2 ? current : closest;
1394
+ }, null);
1395
+ return result;
1396
+ })
1397
+ });
1615
1398
  var levenshteinDistance = (str1, str2) => {
1616
1399
  const m = str1.length;
1617
1400
  const n = str2.length;
@@ -1631,27 +1414,28 @@ var levenshteinDistance = (str1, str2) => {
1631
1414
  };
1632
1415
 
1633
1416
  // src/research/research.ts
1634
- import { Schema as Schema9 } from "effect";
1635
- import { AgentStatusReport as AgentStatusReport2, ConsolePrinter, ToolRegistry as ToolRegistry2 } from "@dxos/ai";
1636
- import { create as create5 } from "@dxos/echo-schema";
1637
- import { AiService as AiService3, CredentialsService, DatabaseService as DatabaseService2, defineFunction as defineFunction3, TracingService } from "@dxos/functions";
1638
- import { log as log9 } from "@dxos/log";
1417
+ import { AiToolkit as AiToolkit4 } from "@effect/ai";
1418
+ import { Effect as Effect6, Layer as Layer2, Schema as Schema8 } from "effect";
1419
+ import { AiService as AiService2, ConsolePrinter } from "@dxos/ai";
1420
+ import { defineFunction as defineFunction3, TracingService } from "@dxos/functions";
1421
+ import { log as log8 } from "@dxos/log";
1639
1422
  import { DataTypes } from "@dxos/schema";
1640
1423
 
1641
1424
  // src/research/graph.ts
1642
- import { Schema as Schema8, identity, Option as Option2, SchemaAST } from "effect";
1643
- import { createTool as createTool3, ToolResult as ToolResult3 } from "@dxos/ai";
1644
- import { Query as Query2, Filter as Filter2 } from "@dxos/echo";
1425
+ import { AiTool as AiTool3, AiToolkit as AiToolkit3 } from "@effect/ai";
1426
+ import { Context as Context3, Effect as Effect5, identity, Option as Option2, Schema as Schema7, SchemaAST } from "effect";
1427
+ import { Filter as Filter2, Query as Query2 } from "@dxos/echo";
1645
1428
  import { isEncodedReference } from "@dxos/echo-protocol";
1646
- import { EntityKind, getSchemaTypename, getTypeAnnotation, getTypeIdentifierAnnotation, create as create4, getEntityKind, getSchemaDXN, ObjectId as ObjectId3, ReferenceAnnotationId, RelationSourceDXNId, RelationTargetDXNId, RelationSourceId, RelationTargetId } from "@dxos/echo-schema";
1429
+ import { create as create3, EntityKind, getEntityKind, getSchemaDXN, getSchemaTypename, getTypeAnnotation, getTypeIdentifierAnnotation, ObjectId as ObjectId3, ReferenceAnnotationId, RelationSourceDXNId, RelationSourceId, RelationTargetDXNId, RelationTargetId } from "@dxos/echo-schema";
1647
1430
  import { mapAst } from "@dxos/effect";
1431
+ import { ContextQueueService, DatabaseService as DatabaseService4 } from "@dxos/functions";
1648
1432
  import { DXN as DXN2 } from "@dxos/keys";
1649
- import { log as log8 } from "@dxos/log";
1650
- import { deepMapValues, isNonNullable as isNonNullable2 } from "@dxos/util";
1433
+ import { log as log7 } from "@dxos/log";
1434
+ import { deepMapValues, isNonNullable } from "@dxos/util";
1651
1435
  var __dxlog_file8 = "/__w/dxos/dxos/packages/core/assistant/src/research/graph.ts";
1652
- var Subgraph = Schema8.Struct({
1436
+ var Subgraph = Schema7.Struct({
1653
1437
  /** Objects and relations. */
1654
- objects: Schema8.Array(Schema8.Any)
1438
+ objects: Schema7.Array(Schema7.Any)
1655
1439
  });
1656
1440
  var findRelatedSchema = async (db, anchor) => {
1657
1441
  const allSchemas = [
@@ -1677,39 +1461,65 @@ var isSchemaAddressableByDxn = (schema, dxn) => {
1677
1461
  }
1678
1462
  return false;
1679
1463
  };
1680
- var createLocalSearchTool = (db, queue) => {
1681
- return createTool3("search", {
1682
- name: "local_search",
1683
- description: "Search the local database for information using a vector index",
1684
- schema: Schema8.Struct({
1685
- query: Schema8.String.annotations({
1686
- description: "The query to search for. Could be a question or a topic or a set of keywords."
1687
- })
1688
- }),
1689
- execute: async ({ query }) => {
1690
- const { objects } = await db.query(Query2.select(Filter2.text(query, {
1691
- type: "vector"
1692
- }))).run();
1693
- const results = [
1694
- ...objects
1695
- ];
1696
- if (queue) {
1697
- const queueObjects = await queue.queryObjects();
1698
- results.push(...queueObjects);
1699
- }
1700
- return ToolResult3.Success(`
1701
- <local_context>
1702
- ${JSON.stringify(results, null, 2)}
1703
- </local_context>
1704
- `);
1464
+ var LocalSearchToolkit = class extends AiToolkit3.make(AiTool3.make("search_local_search", {
1465
+ description: "Search the local database for information using a vector index",
1466
+ parameters: {
1467
+ query: Schema7.String.annotations({
1468
+ description: "The query to search for. Could be a question or a topic or a set of keywords."
1469
+ })
1470
+ },
1471
+ success: Schema7.Unknown,
1472
+ failure: Schema7.Never
1473
+ }).addRequirement()) {
1474
+ };
1475
+ var LocalSearchHandler = LocalSearchToolkit.toLayer({
1476
+ search_local_search: Effect5.fn(function* ({ query }) {
1477
+ const { objects } = yield* DatabaseService4.runQuery(Query2.select(Filter2.text(query, {
1478
+ type: "vector"
1479
+ })));
1480
+ const results = [
1481
+ ...objects
1482
+ ];
1483
+ const contextQueue = yield* Effect5.serviceOption(ContextQueueService);
1484
+ if (Option2.isSome(contextQueue)) {
1485
+ const queueObjects = yield* Effect5.promise(() => contextQueue.value.contextQueue.queryObjects());
1486
+ results.push(...queueObjects);
1705
1487
  }
1488
+ return `
1489
+ <local_context>
1490
+ ${JSON.stringify(results, null, 2)}
1491
+ </local_context>
1492
+ `;
1493
+ })
1494
+ });
1495
+ var GraphWriterSchema = class extends Context3.Tag("GraphWriterSchema")() {
1496
+ };
1497
+ var makeGraphWriterToolkit = ({ schema }) => {
1498
+ return AiToolkit3.make(AiTool3.make("graph_writer", {
1499
+ description: "Write to the local graph database",
1500
+ parameters: createExtractionSchema(schema).fields,
1501
+ success: Schema7.Unknown,
1502
+ failure: Schema7.Never
1503
+ }).addRequirement().annotateContext(Context3.make(GraphWriterSchema, {
1504
+ schema
1505
+ })));
1506
+ };
1507
+ var makeGraphWriterHandler = (toolkit) => {
1508
+ const { schema } = Context3.get(toolkit.tools.graph_writer.annotations, GraphWriterSchema);
1509
+ return toolkit.toLayer({
1510
+ graph_writer: Effect5.fn(function* (input) {
1511
+ const { db } = yield* DatabaseService4;
1512
+ const contextQueue = yield* Effect5.serviceOption(ContextQueueService);
1513
+ const data = yield* Effect5.promise(() => sanitizeObjects(schema, input, db, contextQueue.pipe(Option2.getOrUndefined)?.contextQueue));
1514
+ return data;
1515
+ })
1706
1516
  });
1707
1517
  };
1708
1518
  var createExtractionSchema = (types) => {
1709
- return Schema8.Struct({
1519
+ return Schema7.Struct({
1710
1520
  ...Object.fromEntries(types.map(preprocessSchema).map((schema, index) => [
1711
1521
  `objects_${getSanitizedSchemaName(types[index])}`,
1712
- Schema8.optional(Schema8.Array(schema)).annotations({
1522
+ Schema7.optional(Schema7.Array(schema)).annotations({
1713
1523
  description: `The objects of type: ${getSchemaDXN(types[index])?.asTypeDXN().type}. ${SchemaAST.getDescriptionAnnotation(types[index].ast).pipe(Option2.getOrElse(() => ""))}`
1714
1524
  })
1715
1525
  ]))
@@ -1764,22 +1574,22 @@ var sanitizeObjects = async (types, data, db, queue) => {
1764
1574
  if (getEntityKind(entry.schema) === "relation") {
1765
1575
  const sourceDxn = resolveId(data2.source);
1766
1576
  if (!sourceDxn) {
1767
- log8.warn("source not found", {
1577
+ log7.warn("source not found", {
1768
1578
  source: data2.source
1769
1579
  }, {
1770
1580
  F: __dxlog_file8,
1771
- L: 214,
1581
+ L: 262,
1772
1582
  S: void 0,
1773
1583
  C: (f, a) => f(...a)
1774
1584
  });
1775
1585
  }
1776
1586
  const targetDxn = resolveId(data2.target);
1777
1587
  if (!targetDxn) {
1778
- log8.warn("target not found", {
1588
+ log7.warn("target not found", {
1779
1589
  target: data2.target
1780
1590
  }, {
1781
1591
  F: __dxlog_file8,
1782
- L: 218,
1592
+ L: 266,
1783
1593
  S: void 0,
1784
1594
  C: (f, a) => f(...a)
1785
1595
  });
@@ -1801,14 +1611,14 @@ var sanitizeObjects = async (types, data, db, queue) => {
1801
1611
  const objects = [
1802
1612
  ...dbObjects,
1803
1613
  ...queueObjects
1804
- ].filter(isNonNullable2);
1805
- log8.info("objects", {
1614
+ ].filter(isNonNullable);
1615
+ log7.info("objects", {
1806
1616
  dbObjects,
1807
1617
  queueObjects,
1808
1618
  existingIds
1809
1619
  }, {
1810
1620
  F: __dxlog_file8,
1811
- L: 239,
1621
+ L: 287,
1812
1622
  S: void 0,
1813
1623
  C: (f, a) => f(...a)
1814
1624
  });
@@ -1839,7 +1649,7 @@ var sanitizeObjects = async (types, data, db, queue) => {
1839
1649
  }
1840
1650
  }
1841
1651
  if (!skip) {
1842
- const obj = create4(schema, data2);
1652
+ const obj = create3(schema, data2);
1843
1653
  enitties.set(obj.id, obj);
1844
1654
  return [
1845
1655
  obj
@@ -1848,161 +1658,159 @@ var sanitizeObjects = async (types, data, db, queue) => {
1848
1658
  return [];
1849
1659
  });
1850
1660
  };
1851
- var SoftRef = Schema8.Struct({
1852
- "/": Schema8.String
1661
+ var SoftRef = Schema7.Struct({
1662
+ "/": Schema7.String
1853
1663
  }).annotations({
1854
1664
  description: "Reference to another object."
1855
1665
  });
1856
1666
  var preprocessSchema = (schema) => {
1857
1667
  const isRelationSchema = getEntityKind(schema) === "relation";
1858
- const go = (ast) => {
1668
+ const go = (ast, visited = /* @__PURE__ */ new Set()) => {
1669
+ if (visited.has(ast)) {
1670
+ return ast;
1671
+ }
1672
+ visited.add(ast);
1859
1673
  if (SchemaAST.getAnnotation(ast, ReferenceAnnotationId).pipe(Option2.isSome)) {
1860
1674
  return SoftRef.ast;
1861
1675
  }
1862
- return mapAst(ast, go);
1676
+ return mapAst(ast, (child) => go(child, visited));
1863
1677
  };
1864
- return Schema8.make(mapAst(schema.ast, go)).pipe(Schema8.omit("id"), Schema8.extend(Schema8.Struct({
1865
- id: Schema8.String.annotations({
1678
+ return Schema7.make(mapAst(schema.ast, (ast) => go(ast))).pipe(Schema7.omit("id"), Schema7.extend(Schema7.Struct({
1679
+ id: Schema7.String.annotations({
1866
1680
  description: "The id of this object. Come up with a unique id based on your judgement."
1867
1681
  })
1868
- })), isRelationSchema ? Schema8.extend(Schema8.Struct({
1869
- source: Schema8.String.annotations({
1682
+ })), isRelationSchema ? Schema7.extend(Schema7.Struct({
1683
+ source: Schema7.String.annotations({
1870
1684
  description: "The id of the source object for this relation."
1871
1685
  }),
1872
- target: Schema8.String.annotations({
1686
+ target: Schema7.String.annotations({
1873
1687
  description: "The id of the target object for this relation."
1874
1688
  })
1875
1689
  })) : identity);
1876
1690
  };
1877
- var createGraphWriterTool = ({ db, queue, schema, onDone = async (x) => x }) => {
1878
- return createTool3("graph", {
1879
- name: "writer",
1880
- description: "Write to the local graph database",
1881
- schema: createExtractionSchema(schema),
1882
- execute: async (input) => {
1883
- const data = await sanitizeObjects(schema, input, db, queue);
1884
- return ToolResult3.Success(await onDone(data));
1885
- }
1886
- });
1887
- };
1888
1691
 
1889
1692
  // raw-loader:./instructions-research.tpl?raw
1890
- var instructions_research_default = "You are the Research Agent.\n\nThe Research Agent is an expert assistant that conducts in-depth research using real-time web search.\nThe Research Agent outputs results in a structured format matching the schema provided.\n\nThe Research Agent is equipped with the ability to:\n\n- Generate precise and effective search queries \n- Request web pages by query (through a `web_search` tool)\n- Read the full content of retrieved pages\n- Synthesize accurate, clear, and structured answers using reliable information from the retrieved content\n- Search the local database for information using a vector index (through a `local_search` tool)\n\nThe Research Agent always follows these principles:\n\n- Relevance First: The Research Agent only returns facts supported by content in retrieved web pages. The Research Agent never fabricates or guesses information.\n- Summarize, Don't Copy: The Research Agent synthesizes and rephrases content in its own words. The Research Agent quotes only when necessary.\n- Multiple Sources: The Research Agent cross-references at least 2 sources before drawing conclusions, unless the information is directly stated and non-controversial.\n- Transparency: The Research Agent mentions which sources were used and explains how it arrived at conclusions.\n- Accuracy Over Brevity: The Research Agent prefers detailed, technically accurate explanations over shallow summaries.\n- The Research Agent admits uncertainty rather than misleading.\n- The Research Agent picks the most concrete schema types for extracted information.\n- The Research Agent fills schema fields completely with information it is confident about, and omits fields it is not confident about.\n- When outputting results, the Research Agent adds extra data that fits the schema even if not directly related to the user's question.\n- The Research Agent creates relations and references between new objects found and what's already in the database.\n- The Research Agent does not create objects that are already in the database.\n- The Research Agent re-uses existing object IDs as references when enriching existing objects.\n\nThe Research Agent may be asked for:\n\n- Technical explanations\n- Literature reviews \n- Comparisons\n- Emerging trends\n- Implementation strategies\n\nThe Research Agent begins by interpreting the user's request, then:\n\nThe Research Agent breaks it into sub-questions (if applicable).\n\nFor each sub-question, the Research Agent generates a clear, concise web search query.\n\nThe Research Agent uses `web_search`(query) to retrieve information.\n\nThe Research Agent extracts and synthesizes relevant answers.\n\nThe Research Agent's output includes:\n\n- A clear, structured answer to the user's question\n- A citation list or link list of sources used\n\nOptionally, the Research Agent provides follow-up suggestions or questions for deeper inquiry.\n\nHere's how the Research Agent operates:\n\n1. The Research Agent analyzes the user's request and identifies key topics to search for (3 or more), printing them out.\n2. The Research Agent performs a web search for each topic.\n3. The Research Agent reads and analyzes results, cross references information from multiple sources, and represents conflicting information as ranges of possible values.\n\n4. The Research Agent searches the local database for information using a vector index that might link to the user's question.\n6. The Research Agent creates relations and references between new objects and existing database objects when related, using existing object IDs as references.\n7. The Research Agent selects the most concrete schema types for extracted information, using multiple types as needed, and prints its decision and reasoning.\n5. The Research Agent creates a clear, structured answer to the user's question.\n8. The Research Agent submits results using the specific schema.\n\nIMPORTANT:\n\n- The Research Agent always runs the `local_search` tool to search the local database at least once before submitting results.\n- The Research Agent does not create objects that already exist in the database.\n- Ids that are not in the database are human-readable strings like `ivan_zhao_1`.\n\nStatus reporting:\n\nThe Research Agent reports its status frequently using the `<status>` tags: <status>Searching for Google Founders</status>\nThe Research Agent reports its status in-between each tool call and before submitting results.\n\n<example>\n\nBased on my research, I can now provide information about Google and it's founders.\n\nThe following objects are already in the database, I will not submit them again, but I'll re-use their IDs as references:\n\n- 01JWRDEHPB5TT2JQQQC15038BT Google\n- 01JWRDEHPA14CYW2NW9FAH6DJJ Larry Page\n- 01JWRDEHPBN0BBJP57B9S108W6 Sergey Brin\n\nI will use the following schema to construct new objects:\n\n- type:dxos.org/type/Organization for Alphabet Inc.\n- type:dxos.org/type/Person for Ivan Zhao\n- type:dxos.org/type/Person for Simon Last\n- dxn:type:dxos.org/relation/Employer for Ivan's employer\n- dxn:type:dxos.org/relation/Employer for Simon's employer\n\n<status>Formatting results</status>\n\n</example>";
1693
+ var instructions_research_default = "You are the Research Agent.\n\nThe Research Agent is an expert assistant that conducts in-depth research using real-time web search.\nThe Research Agent outputs results in a structured format matching the schema provided.\n\nThe Research Agent is equipped with the ability to:\n\n- Generate precise and effective search queries \n- Request web pages by query (through a `web_search` tool)\n- Read the full content of retrieved pages\n- Synthesize accurate, clear, and structured answers using reliable information from the retrieved content\n- Search the local database for information using a vector index (through a `local_search` tool)\n\nThe Research Agent always follows these principles:\n\n- Relevance First: The Research Agent only returns facts supported by content in retrieved web pages. The Research Agent never fabricates or guesses information.\n- Summarize, Don't Copy: The Research Agent synthesizes and rephrases content in its own words. The Research Agent quotes only when necessary.\n- Multiple Sources: The Research Agent cross-references at least 2 sources before drawing conclusions, unless the information is directly stated and non-controversial.\n- Transparency: The Research Agent mentions which sources were used and explains how it arrived at conclusions.\n- Accuracy Over Brevity: The Research Agent prefers detailed, technically accurate explanations over shallow summaries.\n- The Research Agent admits uncertainty rather than misleading.\n- The Research Agent picks the most concrete schema types for extracted information.\n- The Research Agent fills schema fields completely with information it is confident about, and omits fields it is not confident about.\n- When outputting results, the Research Agent adds extra data that fits the schema even if not directly related to the user's question.\n- The Research Agent creates relations and references between new objects found and what's already in the database.\n- The Research Agent does not create objects that are already in the database.\n- The Research Agent re-uses existing object IDs as references when enriching existing objects.\n- The Research Agent ALWAYS calls the `graph_writer` at the end to save the data. This conversation will be delted, so only the data written to the graph will be preserved.\n\nThe Research Agent may be asked for:\n\n- Technical explanations\n- Literature reviews \n- Comparisons\n- Emerging trends\n- Implementation strategies\n\nThe Research Agent begins by interpreting the user's request, then:\n\nThe Research Agent breaks it into sub-questions (if applicable).\n\nFor each sub-question, the Research Agent generates a clear, concise web search query.\n\nThe Research Agent uses `web_search`(query) to retrieve information.\n\nThe Research Agent extracts and synthesizes relevant answers.\n\nThe Research Agent's output includes:\n\n- A clear, structured answer to the user's question\n- A citation list or link list of sources used\n\nOptionally, the Research Agent provides follow-up suggestions or questions for deeper inquiry.\n\nHere's how the Research Agent operates:\n\n1. The Research Agent analyzes the user's request and identifies key topics to search for (3 or more), printing them out.\n2. The Research Agent performs a web search for each topic.\n3. The Research Agent reads and analyzes results, cross references information from multiple sources, and represents conflicting information as ranges of possible values.\n\n4. The Research Agent searches the local database for information using a vector index that might link to the user's question.\n6. The Research Agent creates relations and references between new objects and existing database objects when related, using existing object IDs as references.\n7. The Research Agent selects the most concrete schema types for extracted information, using multiple types as needed, and prints its decision and reasoning.\n5. The Research Agent creates a clear, structured answer to the user's question.\n8. The Research Agent submits results using the specific schema.\n\nIMPORTANT:\n\n- The Research Agent always runs the `local_search` tool to search the local database at least once before submitting results.\n- The Research Agent does not create objects that already exist in the database.\n- Ids that are not in the database are human-readable strings like `ivan_zhao_1`.\n\nStatus reporting:\n\nThe Research Agent reports its status frequently using the `<status>` tags: <status>Searching for Google Founders</status>\nThe Research Agent reports its status in-between each tool call and before submitting results.\n\n<example>\n\nBased on my research, I can now provide information about Google and it's founders.\n\nThe following objects are already in the database, I will not submit them again, but I'll re-use their IDs as references:\n\n- 01JWRDEHPB5TT2JQQQC15038BT Google\n- 01JWRDEHPA14CYW2NW9FAH6DJJ Larry Page\n- 01JWRDEHPBN0BBJP57B9S108W6 Sergey Brin\n\nI will use the following schema to construct new objects:\n\n- type:dxos.org/type/Organization for Alphabet Inc.\n- type:dxos.org/type/Person for Ivan Zhao\n- type:dxos.org/type/Person for Simon Last\n- dxn:type:dxos.org/relation/Employer for Ivan's employer\n- dxn:type:dxos.org/relation/Employer for Simon's employer\n\n<status>Formatting results</status>\n\n</example>";
1891
1694
 
1892
1695
  // src/research/research.ts
1893
1696
  var __dxlog_file9 = "/__w/dxos/dxos/packages/core/assistant/src/research/research.ts";
1894
1697
  var researchFn = defineFunction3({
1895
1698
  description: "Research the web for information",
1896
- inputSchema: Schema9.Struct({
1897
- query: Schema9.String.annotations({
1699
+ inputSchema: Schema8.Struct({
1700
+ query: Schema8.String.annotations({
1898
1701
  description: "The query to search for."
1899
1702
  }),
1900
1703
  // TOOD(burdon): Move to context.
1901
- mockSearch: Schema9.optional(Schema9.Boolean).annotations({
1704
+ mockSearch: Schema8.optional(Schema8.Boolean).annotations({
1902
1705
  description: "Whether to use the mock search tool.",
1903
1706
  default: false
1904
1707
  })
1905
1708
  }),
1906
- outputSchema: Schema9.Struct({
1907
- // result: Schema.String,
1908
- result: Schema9.Any
1709
+ outputSchema: Schema8.Struct({
1710
+ result: Schema8.Unknown
1909
1711
  }),
1910
- handler: async ({ data: { query, mockSearch }, context }) => {
1911
- const ai = context.getService(AiService3);
1912
- const credentials = context.getService(CredentialsService);
1913
- const { db } = context.getService(DatabaseService2);
1914
- const tracing = context.getService(TracingService);
1915
- tracing.write(create5(AgentStatusReport2, {
1712
+ handler: Effect6.fnUntraced(function* ({ data: { query, mockSearch } }) {
1713
+ yield* TracingService.emitStatus({
1916
1714
  message: "Researching..."
1917
- }));
1918
- const exaCredential = await credentials.getCredential({
1919
- service: "exa.ai"
1920
1715
  });
1921
- const searchTool = mockSearch ? createMockExaTool() : createExaTool({
1922
- apiKey: exaCredential.apiKey
1716
+ const graphWriteToolkit = makeGraphWriterToolkit({
1717
+ schema: DataTypes
1923
1718
  });
1719
+ const toolkit = yield* AiToolkit4.merge(ExaToolkit, LocalSearchToolkit, graphWriteToolkit).pipe(Effect6.provide(Layer2.mergeAll(mockSearch ? MockExaHandler : LiveExaHandler, LocalSearchHandler, makeGraphWriterHandler(graphWriteToolkit))));
1924
1720
  const printer = new ConsolePrinter();
1925
- const session = new AISession({
1926
- operationModel: "configured"
1927
- });
1721
+ const session = new AiSession();
1928
1722
  session.message.on((message) => printer.printMessage(message));
1929
1723
  session.userMessage.on((message) => printer.printMessage(message));
1930
1724
  session.block.on((block) => printer.printContentBlock(block));
1931
- session.statusReport.on((status) => {
1932
- log9.info("[agent] status", {
1933
- status
1934
- }, {
1935
- F: __dxlog_file9,
1936
- L: 58,
1937
- S: void 0,
1938
- C: (f, a) => f(...a)
1939
- });
1940
- tracing.write(status);
1941
- });
1942
- session.streamEvent.on((event) => log9("stream", {
1725
+ session.streamEvent.on((event) => log8("stream", {
1943
1726
  event
1944
1727
  }, {
1945
1728
  F: __dxlog_file9,
1946
- L: 61,
1947
- S: void 0,
1729
+ L: 62,
1730
+ S: this,
1948
1731
  C: (f, a) => f(...a)
1949
1732
  }));
1950
- const graphWriteTool = createGraphWriterTool({
1951
- db,
1952
- schema: DataTypes
1953
- });
1954
- log9.info("graphWriteTool", {
1955
- schema: graphWriteTool.parameters
1956
- }, {
1957
- F: __dxlog_file9,
1958
- L: 64,
1959
- S: void 0,
1960
- C: (f, a) => f(...a)
1961
- });
1962
- const result = await session.run({
1963
- client: ai.client,
1964
- systemPrompt: instructions_research_default,
1965
- artifacts: [],
1966
- tools: [
1967
- searchTool.id,
1968
- graphWriteTool.id
1969
- ],
1970
- history: [],
1733
+ const result = yield* session.run({
1971
1734
  prompt: query,
1972
- toolResolver: new ToolRegistry2([
1973
- searchTool,
1974
- graphWriteTool
1975
- ])
1735
+ history: [],
1736
+ systemPrompt: instructions_research_default,
1737
+ toolkit
1976
1738
  });
1977
1739
  return {
1978
1740
  result
1979
1741
  };
1980
- }
1742
+ }, Effect6.provide(AiService2.model("@anthropic/claude-3-5-sonnet-20241022")))
1981
1743
  });
1982
1744
 
1745
+ // src/templates/prompt.ts
1746
+ import { Template } from "@dxos/blueprints";
1747
+
1748
+ // raw-loader:./assistant.tpl?raw
1749
+ var assistant_default = "{{! System Prompt }}\n\nYou are a friendly, advanced AI assistant capable of creating and managing artifacts from available data and tools.\nYour task is to process user commands and questions and decide how best to respond.\nIn some cases, you will need to create or reference data objects called artifacts.\n\nFollow these guidelines carefully:\n\n{{section}}. Decision-making:\n\n{{#if cot}}\nBefore responding, explain your reasoning and include your detailed chain-of-thought in a <cot> tag.\n{{/if}}\n\nInclude the following steps:\n\n- Analyze the structure and type of the content in the user's message.\n- Can you complete the task using the available artifact definitions?\n- If you can't complete the task using the available artifact definitions, query the list of available artifact definitions using the appropriate tool.\n- Identify which artifact definitions are relevant to the user's request.\n- Evaluate the potential benefits of creating an artifact vs. normal processing for each identified element.\n- Make a final decision on whether to create an artifact and explain your reasoning.\n- Are the required artifact definitions already available?\n- If not, select which artifact definition(s) will be the most relevant and require them using the require_artifact_definitions tool.\n- The require'd artifact tools will be available for use after require.\n- If creating an artifact, outline how you will structure it within the response.\n- Decide if the artifact needs to be shown to the user.\n- Call the show tool to show the artifact to the user.\n- If you ask the user a multiple choice question, then present each of the possible answers as concise text inside <option> tags inside a well formed <select> tag.\n- If you have suggestions for follow-up actions then present each action as text within a <suggest> tag.\n- Your reasoning must include: whether to use artifacts or not, to create one or query, whether to show the artifact to the user, and how to structure the response.\n\nIf the user asks for a list of tools, then just emit a single self-closing <tool-list/> tag instead of listing the tools.The tag will be replaced with the list of tools when the response is rendered.\nDo not list the tools or artifacts in your response, only emit the tag.\nDo not mention the tag anywhere else in your response unless you are rendering a tool list.\n\n{{section}}. Artifacts:\n\n- Determine if the interaction involves an artifact. Prefer artifacts for tables, lists, spreadsheets, kanbans, games, images, and other structured data.\n- Determine if the user is explicitly talking about creating a new artifact, or wants to use an existing artifact.\n- If it is ambiguous, query for existing artifacts first and then decide.\n- If you decide to create an artifact, call the associated tool to create the artifact.\n- Artifacts are stored in the database. Tools are used to create and query artifacts.\n- If you are unsure about creating an artifact ask the user for clarification.\n\n{{#if artifacts}}\n{{section}}. Artifact Rules:\n\n- Artifacts are mutable objects that can change over the course of the conversation.\n- Always re-query the artifact using the tool (like query or inspect) to get the latest state of the artifact before answering the user.\n- You must never generate the id of the artifact; only recall the ids that are already in the history.\n- Artifacts are created by requiring the specific artifact using the require_artifact tool and creating it by calling the associated tool.\n\n{{section}}. Artifact Providers:\n\n{{#each artifacts}}\n- {{this}}\n{{/each}}\n{{/if}}\n\n{{#if associatedArtifact}}\n{{section}}. Associated artifact:\n\nThe following ID and typename identify the artifact associated with this conversation.\nThis conversation appears alongside the associated artifact as a peer, and the user is likely to make reference to and requests about it.\nYou can interact with this artifact using tools.\n\nID: {{associatedArtifact.id}}\nTypename: {{associatedArtifact.typename}}\n{{/if}}\n\n{{#if suggestions}}\n{{section}}. Suggested actions:\n\n- You can add suggested actions at the end of your response.\n- Suggested actions should be very concise and start with a verb and be phrased as a command to an agent -- not a question to the user.\n- Suggested actions must be in the form of a user instruction that you can follow.\n- Suggested actions could include actions that create artifacts.\n- Suggested actions must be enclosed in a <suggest> tag and on a separate line.\n Examples:\n <suggest>Show the data on a map.</suggest>\n <suggest>Create a kanban from the table.</suggest>\n\n- If you have asked a multiple choice question, then present each of the possible answers as concise text inside <option> tags inside a well formed <select> tag.\n Example:\n <select><option>Yes</option><option>No</option></select>\n{{/if}}\n\n{{section}}. Content proposals:\n\nYou can propose content to add to associated artifacts. Enclose the content you are proposing to add in a <proposal> tag on a separate line.\nFor example:\n<proposal>Apples add a delightful crunch and natural sweetness to salads</proposal>\n\n{{section}}. Output Formats:\n\nIt is very important to respond in the correct format.\n\n{{#if cot}}\n- Your detailed chain-of-thought must be in the form of a markdown list enclosed in <cot> tags.\n- The <cot> tag should be the first thing in your response.\n{{/if}}\n- Suggested actions must be enclosed in a <suggest> tag and on a separate line.\n- Content proposals must be enclosed in a <proposal> tag and on a separate line.\n\nReferences:\n\n- Both user and you can reference external data in the markdown format: [label][URI].\n- If you get references back from a tool call, you can render them as is by preserving the ID literally.\n\n{{instructions}}";
1750
+
1751
+ // src/templates/prompt.ts
1752
+ var createSystemPrompt = (options) => {
1753
+ return Template.createPrompt(assistant_default, options);
1754
+ };
1755
+
1983
1756
  // src/types.ts
1757
+ import { Schema as Schema9 } from "effect";
1758
+ import { DXN as DXN3, LOCAL_SPACE_TAG } from "@dxos/keys";
1984
1759
  var createArtifactElement = (id) => `<artifact id=${id} />`;
1760
+ var ArtifactId = class extends Schema9.String.annotations({
1761
+ description: `
1762
+ The ID of the referenced object. Formats accepted:
1763
+ - DXN (dxn:echo:@:XXXXX). DXNs can be prepended with an @ symbol for compatibility with in-text references.
1764
+ - space ID, object ID tuple (spaceID:objectID)
1765
+ - Only object ID that is assumed to be in the current space (XXXXX)
1766
+ `,
1767
+ examples: [
1768
+ "dxn:echo:@:XXXXX",
1769
+ "@dxn:echo:@:XXXXX",
1770
+ "spaceID:objectID",
1771
+ "XXXXX"
1772
+ ]
1773
+ }) {
1774
+ static toDXN(reference, owningSpaceId) {
1775
+ if (reference.startsWith("@dxn:")) {
1776
+ return DXN3.parse(reference.slice(1));
1777
+ } else if (reference.startsWith("dxn:")) {
1778
+ return DXN3.parse(reference);
1779
+ } else if (/^[A-Z0-9]+:[A-Z0-9]+$/.test(reference)) {
1780
+ const [spaceId, objectId] = reference.split(":");
1781
+ return new DXN3(DXN3.kind.ECHO, [
1782
+ spaceId === owningSpaceId ? LOCAL_SPACE_TAG : spaceId,
1783
+ objectId
1784
+ ]);
1785
+ } else if (/^[A-Z0-9]+$/.test(reference)) {
1786
+ return DXN3.fromLocalObjectId(reference);
1787
+ } else {
1788
+ throw new Error(`Unable to parse object reference: ${reference}`);
1789
+ }
1790
+ }
1791
+ };
1985
1792
  export {
1986
- AIServiecOverloadedError,
1987
- AISession,
1793
+ AiSession,
1794
+ ArtifactDiffResolver,
1795
+ ArtifactId,
1988
1796
  Bindings,
1989
- Blueprint,
1990
- BlueprintRegistry,
1991
1797
  ContextBinder,
1992
1798
  ContextBinding,
1993
1799
  Conversation,
1800
+ ExaToolkit,
1994
1801
  ExtractionInput,
1995
1802
  ExtractionOutput,
1803
+ LiveExaHandler,
1804
+ LocalSearchHandler,
1805
+ LocalSearchToolkit,
1806
+ MockExaHandler,
1996
1807
  ReferencedQuotes,
1997
1808
  Subgraph,
1998
1809
  VersionPin,
1999
1810
  combineNerTokens,
2000
1811
  createArtifactElement,
2001
- createExaTool,
2002
1812
  createExtractionSchema,
2003
- createGraphWriterTool,
2004
- createLocalSearchTool,
2005
- createMockExaTool,
1813
+ createSystemPrompt,
2006
1814
  createTokenGroups,
2007
1815
  extractFullEntities,
2008
1816
  extractionAnthropicFn,
@@ -2012,6 +1820,10 @@ export {
2012
1820
  getNer,
2013
1821
  getSanitizedSchemaName,
2014
1822
  insertReferences,
1823
+ makeGraphWriterHandler,
1824
+ makeGraphWriterToolkit,
1825
+ makeToolExecutionServiceFromFunctions,
1826
+ makeToolResolverFromFunctions,
2015
1827
  processTranscriptMessage,
2016
1828
  researchFn,
2017
1829
  sanitizeObjects