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