@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.
- package/dist/lib/browser/index.mjs +623 -811
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +623 -811
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/context/binder.d.ts +4 -4
- package/dist/types/src/context/binder.d.ts.map +1 -1
- package/dist/types/src/context/binding.d.ts +24 -6
- package/dist/types/src/context/binding.d.ts.map +1 -1
- package/dist/types/src/conversation/conversation.d.ts +12 -18
- package/dist/types/src/conversation/conversation.d.ts.map +1 -1
- package/dist/types/src/errors.d.ts +38 -0
- package/dist/types/src/errors.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +127 -33
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts +1 -1
- package/dist/types/src/extraction/extraction-ner-function/named-entity-recognition.d.ts.map +1 -1
- package/dist/types/src/extraction/extraction.d.ts +100 -42
- package/dist/types/src/extraction/extraction.d.ts.map +1 -1
- package/dist/types/src/functions/index.d.ts +2 -0
- package/dist/types/src/functions/index.d.ts.map +1 -0
- package/dist/types/src/functions/services.d.ts +6 -0
- package/dist/types/src/functions/services.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +2 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/research/exa.d.ts +10 -5
- package/dist/types/src/research/exa.d.ts.map +1 -1
- package/dist/types/src/research/graph.d.ts +18 -8
- package/dist/types/src/research/graph.d.ts.map +1 -1
- package/dist/types/src/research/research.d.ts +1 -1
- package/dist/types/src/research/research.d.ts.map +1 -1
- package/dist/types/src/session/session.d.ts +170 -193
- package/dist/types/src/session/session.d.ts.map +1 -1
- package/dist/types/src/session/version-pin.d.ts +2 -2
- package/dist/types/src/session/version-pin.d.ts.map +1 -1
- package/dist/types/src/templates/index.d.ts +2 -0
- package/dist/types/src/templates/index.d.ts.map +1 -0
- package/dist/types/src/templates/prompt.d.ts +30 -0
- package/dist/types/src/templates/prompt.d.ts.map +1 -0
- package/dist/types/src/types.d.ts +10 -0
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +29 -21
- package/src/context/binder.ts +6 -4
- package/src/context/binding.ts +4 -3
- package/src/conversation/conversation.ts +54 -61
- package/src/errors.ts +10 -0
- package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +6 -18
- package/src/extraction/extraction-llm-function/extraction-llm-function.ts +18 -14
- package/src/extraction/extraction-ner-function/extraction-ner-function.ts +6 -3
- package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +2 -2
- package/src/extraction/extraction-ner-function/named-entity-recognition.ts +1 -1
- package/src/functions/index.ts +5 -0
- package/src/functions/services.ts +139 -0
- package/src/index.ts +2 -2
- package/src/research/exa.ts +56 -59
- package/src/research/graph.test.ts +50 -1
- package/src/research/graph.ts +85 -53
- package/src/research/instructions-research.tpl +1 -0
- package/src/research/research.test.ts +27 -27
- package/src/research/research.ts +50 -53
- package/src/session/__snapshots__/session.test.ts.snap +32 -0
- package/src/session/session.test.ts +90 -55
- package/src/session/session.ts +215 -461
- package/src/session/version-pin.test.ts +2 -21
- package/src/session/version-pin.ts +5 -5
- package/src/summarization/summarization.test.ts +75 -88
- package/src/templates/assistant.tpl +111 -0
- package/src/templates/index.ts +5 -0
- package/src/templates/prompt.ts +45 -0
- package/src/types.ts +40 -1
- package/dist/types/src/blueprint/blueprint.d.ts +0 -41
- package/dist/types/src/blueprint/blueprint.d.ts.map +0 -1
- package/dist/types/src/blueprint/index.d.ts +0 -3
- package/dist/types/src/blueprint/index.d.ts.map +0 -1
- package/dist/types/src/blueprint/registry.d.ts +0 -7
- package/dist/types/src/blueprint/registry.d.ts.map +0 -1
- package/src/blueprint/blueprint.ts +0 -75
- package/src/blueprint/index.ts +0 -6
- 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
|
|
78
|
-
import {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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:
|
|
86
|
-
added:
|
|
87
|
-
removed:
|
|
17
|
+
objects: Schema.Struct({
|
|
18
|
+
added: Schema.Array(Type.Ref(Type.Expando)),
|
|
19
|
+
removed: Schema.Array(Type.Ref(Type.Expando))
|
|
88
20
|
})
|
|
89
|
-
}).pipe(
|
|
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 {
|
|
98
|
+
import { Effect as Effect2 } from "effect";
|
|
167
99
|
import { Event as Event2 } from "@dxos/async";
|
|
168
|
-
import { Obj as Obj3
|
|
169
|
-
import {
|
|
170
|
-
import {
|
|
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 {
|
|
175
|
-
import {
|
|
176
|
-
import {
|
|
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 {
|
|
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/
|
|
184
|
-
import {
|
|
185
|
-
|
|
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
|
|
222
|
-
constructor(_options) {
|
|
124
|
+
var AiSession = class {
|
|
125
|
+
constructor(_options = {}) {
|
|
223
126
|
this._options = _options;
|
|
224
|
-
this.
|
|
127
|
+
this._semaphore = Effect.runSync(Effect.makeSemaphore(1));
|
|
225
128
|
this._pending = [];
|
|
226
129
|
this._history = [];
|
|
227
|
-
this.message =
|
|
228
|
-
this.block =
|
|
229
|
-
this.update =
|
|
230
|
-
this.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.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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:
|
|
153
|
+
L: 126,
|
|
295
154
|
S: this,
|
|
296
155
|
C: (f, a) => f(...a)
|
|
297
156
|
});
|
|
298
|
-
|
|
299
|
-
...
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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:
|
|
179
|
+
L: 155,
|
|
320
180
|
S: this,
|
|
321
181
|
C: (f, a) => f(...a)
|
|
322
182
|
});
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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
|
-
|
|
506
|
-
|
|
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
|
-
})
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
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
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
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
|
-
|
|
576
|
-
|
|
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
|
-
|
|
582
|
-
|
|
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.
|
|
633
|
-
if (block.
|
|
634
|
-
|
|
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
|
-
|
|
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.
|
|
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(
|
|
379
|
+
return queueItems.filter(Obj3.instanceOf(DataType2.Message));
|
|
712
380
|
}
|
|
713
381
|
};
|
|
714
382
|
|
|
715
383
|
// src/extraction/extraction.ts
|
|
716
|
-
import { Schema as
|
|
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
|
|
720
|
-
import { DataType } from "@dxos/schema";
|
|
721
|
-
var
|
|
722
|
-
var ExtractionInput =
|
|
723
|
-
message:
|
|
724
|
-
objects:
|
|
725
|
-
options:
|
|
726
|
-
timeout:
|
|
727
|
-
fallbackToRaw:
|
|
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 =
|
|
731
|
-
message:
|
|
732
|
-
timeElapsed:
|
|
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
|
-
|
|
411
|
+
log2.warn("failed to process message, falling back to raw text", {
|
|
744
412
|
error
|
|
745
413
|
}, {
|
|
746
|
-
F:
|
|
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 {
|
|
430
|
+
import { ToolRegistry, AiService } from "@dxos/ai";
|
|
763
431
|
import { Obj as Obj4 } from "@dxos/echo";
|
|
764
|
-
import { create
|
|
765
|
-
import {
|
|
766
|
-
import { DataType as
|
|
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
|
|
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
|
|
777
|
-
var
|
|
778
|
-
var ReferencedQuotes =
|
|
779
|
-
references:
|
|
780
|
-
id:
|
|
781
|
-
quote:
|
|
782
|
-
})).pipe(
|
|
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
|
-
|
|
463
|
+
log3.info("found quotes in vector index", {
|
|
796
464
|
objects,
|
|
797
465
|
quote
|
|
798
466
|
}, {
|
|
799
|
-
F:
|
|
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(
|
|
834
|
-
const session = new
|
|
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(
|
|
845
|
-
|
|
846
|
-
|
|
512
|
+
Obj4.make(DataType4.Message, {
|
|
513
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
514
|
+
sender: {
|
|
515
|
+
role: "user"
|
|
516
|
+
},
|
|
517
|
+
blocks: [
|
|
847
518
|
{
|
|
848
|
-
|
|
519
|
+
_tag: "text",
|
|
849
520
|
text: `<context>${JSON.stringify(objects)}</context>`
|
|
850
521
|
},
|
|
851
522
|
{
|
|
852
|
-
|
|
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:
|
|
535
|
+
message: create(DataType4.Message, {
|
|
865
536
|
...message,
|
|
866
|
-
blocks: message.blocks.map((block, i) => 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
|
|
879
|
-
import { DatabaseService, defineFunction as defineFunction2 } from "@dxos/functions";
|
|
880
|
-
import { invariant
|
|
881
|
-
import { log as
|
|
882
|
-
import { DataType as
|
|
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
|
|
887
|
-
var
|
|
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
|
-
|
|
893
|
-
F:
|
|
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
|
|
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
|
-
|
|
644
|
+
log5.info("input", {
|
|
974
645
|
message,
|
|
975
646
|
options
|
|
976
647
|
}, {
|
|
977
|
-
F:
|
|
978
|
-
L:
|
|
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(
|
|
654
|
+
const { db } = context.getService(DatabaseService3);
|
|
984
655
|
const entitiesPromise = Promise.all(message.blocks.map(async (block) => {
|
|
985
|
-
|
|
986
|
-
F:
|
|
987
|
-
L:
|
|
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.
|
|
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
|
-
|
|
668
|
+
log5.info("entities", {
|
|
998
669
|
entities
|
|
999
670
|
}, {
|
|
1000
|
-
F:
|
|
1001
|
-
L:
|
|
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
|
-
|
|
1008
|
-
F:
|
|
1009
|
-
L:
|
|
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.
|
|
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.
|
|
689
|
+
text: insertReferences(block._tag, quoteReferences)
|
|
1019
690
|
};
|
|
1020
691
|
});
|
|
1021
|
-
const messageWithReferences =
|
|
692
|
+
const messageWithReferences = create2(DataType5.Message, {
|
|
1022
693
|
...message,
|
|
1023
694
|
blocks: blocksWithReferences
|
|
1024
695
|
});
|
|
1025
|
-
|
|
696
|
+
log5.info("output", {
|
|
1026
697
|
messageWithReferences
|
|
1027
698
|
}, {
|
|
1028
|
-
F:
|
|
1029
|
-
L:
|
|
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 {
|
|
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 {
|
|
1044
|
-
import { log as
|
|
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
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
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 {
|
|
1635
|
-
import {
|
|
1636
|
-
import {
|
|
1637
|
-
import {
|
|
1638
|
-
import { log as
|
|
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 {
|
|
1643
|
-
import {
|
|
1644
|
-
import {
|
|
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 {
|
|
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
|
|
1650
|
-
import { deepMapValues, isNonNullable
|
|
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 =
|
|
1436
|
+
var Subgraph = Schema7.Struct({
|
|
1653
1437
|
/** Objects and relations. */
|
|
1654
|
-
objects:
|
|
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
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
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
|
|
1519
|
+
return Schema7.Struct({
|
|
1710
1520
|
...Object.fromEntries(types.map(preprocessSchema).map((schema, index) => [
|
|
1711
1521
|
`objects_${getSanitizedSchemaName(types[index])}`,
|
|
1712
|
-
|
|
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
|
-
|
|
1577
|
+
log7.warn("source not found", {
|
|
1768
1578
|
source: data2.source
|
|
1769
1579
|
}, {
|
|
1770
1580
|
F: __dxlog_file8,
|
|
1771
|
-
L:
|
|
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
|
-
|
|
1588
|
+
log7.warn("target not found", {
|
|
1779
1589
|
target: data2.target
|
|
1780
1590
|
}, {
|
|
1781
1591
|
F: __dxlog_file8,
|
|
1782
|
-
L:
|
|
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(
|
|
1805
|
-
|
|
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:
|
|
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 =
|
|
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 =
|
|
1852
|
-
"/":
|
|
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
|
|
1865
|
-
id:
|
|
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 ?
|
|
1869
|
-
source:
|
|
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:
|
|
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:
|
|
1897
|
-
query:
|
|
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:
|
|
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:
|
|
1907
|
-
|
|
1908
|
-
result: Schema9.Any
|
|
1709
|
+
outputSchema: Schema8.Struct({
|
|
1710
|
+
result: Schema8.Unknown
|
|
1909
1711
|
}),
|
|
1910
|
-
handler:
|
|
1911
|
-
|
|
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
|
|
1922
|
-
|
|
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
|
|
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.
|
|
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:
|
|
1947
|
-
S:
|
|
1729
|
+
L: 62,
|
|
1730
|
+
S: this,
|
|
1948
1731
|
C: (f, a) => f(...a)
|
|
1949
1732
|
}));
|
|
1950
|
-
const
|
|
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
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
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
|
-
|
|
1987
|
-
|
|
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
|
-
|
|
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
|