@dxos/assistant 0.8.3 → 0.8.4-main.03d5cd7b56
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/README.md +1 -0
- package/dist/lib/neutral/extraction/index.mjs +202 -0
- package/dist/lib/neutral/extraction/index.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +1736 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/types/src/conversation/context.d.ts +156 -0
- package/dist/types/src/conversation/context.d.ts.map +1 -0
- package/dist/types/src/conversation/context.test.d.ts +2 -0
- package/dist/types/src/conversation/context.test.d.ts.map +1 -0
- package/dist/types/src/conversation/index.d.ts +3 -0
- package/dist/types/src/conversation/index.d.ts.map +1 -0
- package/dist/types/src/conversation/session.d.ts +73 -0
- package/dist/types/src/conversation/session.d.ts.map +1 -0
- package/dist/types/src/diff.d.ts +17 -0
- package/dist/types/src/diff.d.ts.map +1 -0
- package/dist/types/src/diff.test.d.ts +2 -0
- package/dist/types/src/diff.test.d.ts.map +1 -0
- package/dist/types/src/errors.d.ts +67 -0
- package/dist/types/src/errors.d.ts.map +1 -0
- package/dist/types/src/execution-graph.d.ts +85 -0
- package/dist/types/src/execution-graph.d.ts.map +1 -0
- package/dist/types/src/execution-graph.test.d.ts +2 -0
- package/dist/types/src/execution-graph.test.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-ner-function/index.d.ts +0 -1
- package/dist/types/src/extraction/extraction-ner-function/index.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 +1066 -215
- package/dist/types/src/extraction/extraction.d.ts.map +1 -1
- package/dist/types/src/extraction/index.d.ts +0 -1
- package/dist/types/src/extraction/index.d.ts.map +1 -1
- package/dist/types/src/extraction/quotes.d.ts +3 -3
- package/dist/types/src/extraction/quotes.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 +17 -0
- package/dist/types/src/functions/services.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +7 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/session/artifact-diff.d.ts +27 -0
- package/dist/types/src/session/artifact-diff.d.ts.map +1 -0
- package/dist/types/src/session/error-handling.d.ts +4 -0
- package/dist/types/src/session/error-handling.d.ts.map +1 -0
- package/dist/types/src/session/format.d.ts +15 -0
- package/dist/types/src/session/format.d.ts.map +1 -0
- package/dist/types/src/session/index.d.ts +5 -1
- package/dist/types/src/session/index.d.ts.map +1 -1
- package/dist/types/src/session/observer.d.ts +23 -0
- package/dist/types/src/session/observer.d.ts.map +1 -0
- package/dist/types/src/session/request.d.ts +104 -0
- package/dist/types/src/session/request.d.ts.map +1 -0
- package/dist/types/src/session/toolkit.d.ts +16 -0
- package/dist/types/src/session/toolkit.d.ts.map +1 -0
- package/dist/types/src/session/version-pin.d.ts +5 -5
- 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/system.d.ts +17 -0
- package/dist/types/src/templates/system.d.ts.map +1 -0
- package/dist/types/src/tracing.d.ts +233 -0
- package/dist/types/src/tracing.d.ts.map +1 -0
- package/dist/types/src/types/artifact.d.ts +28 -0
- package/dist/types/src/types/artifact.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +2 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +43 -38
- package/src/conversation/context.test.ts +52 -0
- package/src/conversation/context.ts +403 -0
- package/src/conversation/index.ts +6 -0
- package/src/conversation/session.ts +323 -0
- package/src/diff.test.ts +74 -0
- package/src/diff.ts +93 -0
- package/src/errors.ts +15 -0
- package/src/execution-graph.test.ts +740 -0
- package/src/execution-graph.ts +519 -0
- package/src/extraction/extraction-ner-function/index.ts +0 -1
- package/src/extraction/extraction-ner-function/named-entity-recognition.test.ts +12 -6
- package/src/extraction/extraction-ner-function/named-entity-recognition.ts +3 -1
- package/src/extraction/extraction.ts +44 -15
- package/src/extraction/index.ts +0 -1
- package/src/extraction/quotes.test.ts +3 -3
- package/src/extraction/quotes.ts +6 -7
- package/src/functions/index.ts +5 -0
- package/src/functions/services.ts +214 -0
- package/src/index.ts +7 -3
- package/src/session/artifact-diff.ts +41 -0
- package/src/session/error-handling.ts +41 -0
- package/src/session/format.ts +147 -0
- package/src/session/index.ts +5 -1
- package/src/session/observer.ts +62 -0
- package/src/session/request.ts +347 -0
- package/src/session/toolkit.ts +47 -0
- package/src/session/version-pin.ts +12 -12
- package/src/templates/index.ts +5 -0
- package/src/templates/instructions/format.tpl +57 -0
- package/src/templates/instructions/system.tpl +96 -0
- package/src/templates/system.ts +42 -0
- package/src/tracing.ts +57 -0
- package/src/types/artifact.ts +89 -0
- package/src/types/index.ts +5 -0
- package/src/typings.d.ts +5 -0
- package/dist/lib/browser/index.mjs +0 -2158
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/node/index.cjs +0 -2178
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node-esm/index.mjs +0 -2160
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/types/bin/chat.d.ts +0 -2
- package/dist/types/bin/chat.d.ts.map +0 -1
- package/dist/types/src/blueprint/ai.test.d.ts +0 -2
- package/dist/types/src/blueprint/ai.test.d.ts.map +0 -1
- package/dist/types/src/blueprint/blueprint.d.ts +0 -55
- package/dist/types/src/blueprint/blueprint.d.ts.map +0 -1
- package/dist/types/src/blueprint/blueprint.test.d.ts +0 -2
- package/dist/types/src/blueprint/blueprint.test.d.ts.map +0 -1
- package/dist/types/src/blueprint/index.d.ts +0 -4
- package/dist/types/src/blueprint/index.d.ts.map +0 -1
- package/dist/types/src/blueprint/logger.d.ts +0 -25
- package/dist/types/src/blueprint/logger.d.ts.map +0 -1
- package/dist/types/src/blueprint/machine.d.ts +0 -143
- package/dist/types/src/blueprint/machine.d.ts.map +0 -1
- package/dist/types/src/blueprint/test-data.d.ts +0 -3
- package/dist/types/src/blueprint/test-data.d.ts.map +0 -1
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts +0 -4
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.d.ts.map +0 -1
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts +0 -2
- package/dist/types/src/extraction/extraction-llm-function/extraction-llm-function.test.d.ts.map +0 -1
- package/dist/types/src/extraction/extraction-llm-function/index.d.ts +0 -2
- package/dist/types/src/extraction/extraction-llm-function/index.d.ts.map +0 -1
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts +0 -208
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.d.ts.map +0 -1
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts +0 -2
- package/dist/types/src/extraction/extraction-ner-function/extraction-ner-function.test.d.ts.map +0 -1
- package/dist/types/src/research/exa.d.ts +0 -7
- package/dist/types/src/research/exa.d.ts.map +0 -1
- package/dist/types/src/research/graph.d.ts +0 -41
- package/dist/types/src/research/graph.d.ts.map +0 -1
- package/dist/types/src/research/graph.test.d.ts +0 -2
- package/dist/types/src/research/graph.test.d.ts.map +0 -1
- package/dist/types/src/research/index.d.ts +0 -4
- package/dist/types/src/research/index.d.ts.map +0 -1
- package/dist/types/src/research/research.d.ts +0 -10
- package/dist/types/src/research/research.d.ts.map +0 -1
- package/dist/types/src/research/research.test.d.ts +0 -2
- package/dist/types/src/research/research.test.d.ts.map +0 -1
- package/dist/types/src/session/session.d.ts +0 -261
- package/dist/types/src/session/session.d.ts.map +0 -1
- package/dist/types/src/session/session.test.d.ts +0 -2
- package/dist/types/src/session/session.test.d.ts.map +0 -1
- package/dist/types/src/session/version-pin.test.d.ts +0 -2
- package/dist/types/src/session/version-pin.test.d.ts.map +0 -1
- package/dist/types/src/summarization/summarization.test.d.ts +0 -2
- package/dist/types/src/summarization/summarization.test.d.ts.map +0 -1
- package/dist/types/src/testing/exa-search-1748337321991.d.ts +0 -38
- package/dist/types/src/testing/exa-search-1748337321991.d.ts.map +0 -1
- package/dist/types/src/testing/exa-search-1748337331526.d.ts +0 -37
- package/dist/types/src/testing/exa-search-1748337331526.d.ts.map +0 -1
- package/dist/types/src/testing/exa-search-1748337344119.d.ts +0 -58
- package/dist/types/src/testing/exa-search-1748337344119.d.ts.map +0 -1
- package/dist/types/src/testing/index.d.ts +0 -3
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/types.d.ts +0 -3
- package/dist/types/src/types.d.ts.map +0 -1
- package/src/blueprint/ai.test.ts +0 -156
- package/src/blueprint/blueprint.test.ts +0 -151
- package/src/blueprint/blueprint.ts +0 -75
- package/src/blueprint/index.ts +0 -7
- package/src/blueprint/logger.ts +0 -155
- package/src/blueprint/machine.ts +0 -251
- package/src/blueprint/test-data.ts +0 -55
- package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +0 -95
- package/src/extraction/extraction-llm-function/extraction-llm-function.ts +0 -65
- package/src/extraction/extraction-llm-function/index.ts +0 -5
- package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +0 -115
- package/src/extraction/extraction-ner-function/extraction-ner-function.ts +0 -54
- package/src/research/exa.ts +0 -100
- package/src/research/graph.test.ts +0 -15
- package/src/research/graph.ts +0 -337
- package/src/research/index.ts +0 -7
- package/src/research/instructions-research.tpl +0 -97
- package/src/research/research.test.ts +0 -190
- package/src/research/research.ts +0 -89
- package/src/session/session.test.ts +0 -229
- package/src/session/session.ts +0 -549
- package/src/session/version-pin.test.ts +0 -26
- package/src/summarization/summarization.test.ts +0 -221
- package/src/testing/exa-search-1748337321991.ts +0 -131
- package/src/testing/exa-search-1748337331526.ts +0 -144
- package/src/testing/exa-search-1748337344119.ts +0 -133
- package/src/testing/index.ts +0 -11
- package/src/typedefs.d.ts +0 -8
- package/src/types.ts +0 -8
- /package/src/extraction/extraction-llm-function/{instructions.tpl → transcription-instructions.tpl} +0 -0
package/src/blueprint/machine.ts
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { Match, Schema } from 'effect';
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
createTool,
|
|
9
|
-
type AiServiceClient,
|
|
10
|
-
Message,
|
|
11
|
-
type MessageContentBlock,
|
|
12
|
-
ToolResult,
|
|
13
|
-
type ToolUseContentBlock,
|
|
14
|
-
type ToolRegistry,
|
|
15
|
-
} from '@dxos/ai';
|
|
16
|
-
import { Event } from '@dxos/async';
|
|
17
|
-
import { Key, Obj } from '@dxos/echo';
|
|
18
|
-
import { type ObjectId } from '@dxos/keys';
|
|
19
|
-
import { log } from '@dxos/log';
|
|
20
|
-
import { isNonNullable } from '@dxos/util';
|
|
21
|
-
|
|
22
|
-
import type { Blueprint, BlueprintStep } from './blueprint';
|
|
23
|
-
import { AISession } from '../session';
|
|
24
|
-
|
|
25
|
-
const SYSTEM_PROMPT = `
|
|
26
|
-
You are a smart Rule-Following Agent.
|
|
27
|
-
Rule-Following Agent executes the command that the user sent in the last message.
|
|
28
|
-
After doing the work, the Rule-Following Agent calls report tool.
|
|
29
|
-
If the Rule-Following agent believes that no action is needed, it calls the report tool with "skipped" status.
|
|
30
|
-
If the Rule-Following Agent is unable to perform the task, it calls the report tool with "bail" status.
|
|
31
|
-
Rule-Following Agent explains the reason it is unable to perform the task before bailing.
|
|
32
|
-
The Rule-Following Agent can express creativity and imagination in the way it performs the task.
|
|
33
|
-
The Rule-Following Agent precisely follows the instructions.
|
|
34
|
-
`;
|
|
35
|
-
|
|
36
|
-
export type BlueprintTraceStep = {
|
|
37
|
-
status: 'done' | 'bailed' | 'skipped';
|
|
38
|
-
stepId: ObjectId;
|
|
39
|
-
comment: string;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export type BlueprintMachineState = {
|
|
43
|
-
history: Message[];
|
|
44
|
-
trace: BlueprintTraceStep[];
|
|
45
|
-
state: 'working' | 'bail' | 'done';
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const INITIAL_STATE: BlueprintMachineState = {
|
|
49
|
-
state: 'working',
|
|
50
|
-
history: [],
|
|
51
|
-
trace: [],
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
type ExecutionOptions = {
|
|
55
|
-
aiClient: AiServiceClient;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Input to the blueprint.
|
|
59
|
-
*/
|
|
60
|
-
input?: unknown;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export type BlueprintEvent =
|
|
64
|
-
| { type: 'begin'; invocationId: string }
|
|
65
|
-
| { type: 'end'; invocationId: string }
|
|
66
|
-
| { type: 'step-start'; invocationId: string; step: BlueprintStep }
|
|
67
|
-
| { type: 'step-complete'; invocationId: string; step: BlueprintStep }
|
|
68
|
-
| { type: 'message'; invocationId: string; message: Message }
|
|
69
|
-
| { type: 'block'; invocationId: string; block: MessageContentBlock };
|
|
70
|
-
|
|
71
|
-
export interface BlueprintLogger {
|
|
72
|
-
log(event: BlueprintEvent): void;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Blueprint state machine.
|
|
77
|
-
*/
|
|
78
|
-
export class BlueprintMachine {
|
|
79
|
-
public readonly begin = new Event<void>();
|
|
80
|
-
public readonly end = new Event<void>();
|
|
81
|
-
public readonly stepStart = new Event<BlueprintStep>();
|
|
82
|
-
public readonly stepComplete = new Event<BlueprintStep>();
|
|
83
|
-
public readonly message = new Event<Message>();
|
|
84
|
-
public readonly block = new Event<MessageContentBlock>();
|
|
85
|
-
|
|
86
|
-
// TODO(burdon): Replace events with logger?
|
|
87
|
-
private logger?: BlueprintLogger;
|
|
88
|
-
|
|
89
|
-
private _state: BlueprintMachineState = structuredClone(INITIAL_STATE);
|
|
90
|
-
|
|
91
|
-
constructor(
|
|
92
|
-
readonly registry: ToolRegistry,
|
|
93
|
-
readonly blueprint: Blueprint,
|
|
94
|
-
) {}
|
|
95
|
-
|
|
96
|
-
get state(): BlueprintMachineState {
|
|
97
|
-
return this._state;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
setLogger(logger: BlueprintLogger): this {
|
|
101
|
-
this.logger = logger;
|
|
102
|
-
return this;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async runToCompletion(options: ExecutionOptions): Promise<void> {
|
|
106
|
-
const invocationId = Key.ObjectId.random();
|
|
107
|
-
log.info('runToCompletion', { invocationId, options });
|
|
108
|
-
|
|
109
|
-
this.begin.emit();
|
|
110
|
-
this.logger?.log({ type: 'begin', invocationId });
|
|
111
|
-
|
|
112
|
-
let firstStep = true;
|
|
113
|
-
while (this._state.state !== 'done') {
|
|
114
|
-
const input = firstStep ? options.input : undefined;
|
|
115
|
-
firstStep = false;
|
|
116
|
-
|
|
117
|
-
this._state = await this._execStep(invocationId, this._state, { input, aiClient: options.aiClient });
|
|
118
|
-
|
|
119
|
-
const step = this.blueprint.steps.find((step) => step.id === this._state.trace.at(-1)?.stepId)!;
|
|
120
|
-
this.stepComplete.emit(step);
|
|
121
|
-
this.logger?.log({ type: 'step-complete', invocationId, step });
|
|
122
|
-
|
|
123
|
-
if (this._state.state === 'bail') {
|
|
124
|
-
throw new Error('Agent unable to follow the blueprint');
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
this.end.emit();
|
|
129
|
-
this.logger?.log({ type: 'end', invocationId });
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
private async _execStep(
|
|
133
|
-
invocationId: string,
|
|
134
|
-
state: BlueprintMachineState,
|
|
135
|
-
options: ExecutionOptions,
|
|
136
|
-
): Promise<BlueprintMachineState> {
|
|
137
|
-
const prevStep = this.blueprint.steps.findIndex((step) => step.id === this._state.trace.at(-1)?.stepId);
|
|
138
|
-
if (prevStep === this.blueprint.steps.length - 1) {
|
|
139
|
-
throw new Error('Done execution blueprint');
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const nextStep = this.blueprint.steps[prevStep + 1];
|
|
143
|
-
const onLastStep = prevStep === this.blueprint.steps.length - 2;
|
|
144
|
-
|
|
145
|
-
this.stepStart.emit(nextStep);
|
|
146
|
-
this.logger?.log({ type: 'step-start', invocationId, step: nextStep });
|
|
147
|
-
|
|
148
|
-
const ReportSchema = Schema.Struct({
|
|
149
|
-
status: Schema.Literal('done', 'bailed', 'skipped').annotations({
|
|
150
|
-
description: 'The status of the task completion',
|
|
151
|
-
}),
|
|
152
|
-
comment: Schema.String.annotations({
|
|
153
|
-
description:
|
|
154
|
-
'A comment about the task completion. If you bailed, you must explain why in detail (min couple of sentences).',
|
|
155
|
-
}),
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const report = createTool('system', {
|
|
159
|
-
name: 'report',
|
|
160
|
-
description: 'This tool reports that the agent has completed the task or is unable to do so.',
|
|
161
|
-
schema: ReportSchema,
|
|
162
|
-
execute: async (input) => ToolResult.Break(input),
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
const session = new AISession({
|
|
166
|
-
operationModel: 'configured',
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
session.userMessage.pipeInto(this.message);
|
|
170
|
-
session.message.pipeInto(this.message);
|
|
171
|
-
session.block.pipeInto(this.block);
|
|
172
|
-
|
|
173
|
-
const inputMessages = options.input
|
|
174
|
-
? [
|
|
175
|
-
Obj.make(Message, {
|
|
176
|
-
role: 'user',
|
|
177
|
-
content: [taggedDataBlock('input', options.input)],
|
|
178
|
-
}),
|
|
179
|
-
]
|
|
180
|
-
: [];
|
|
181
|
-
inputMessages.forEach((message) => {
|
|
182
|
-
this.message.emit(message);
|
|
183
|
-
this.logger?.log({ type: 'message', invocationId, message });
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
// TODO(wittjosiah): Warn if tool is not found.
|
|
187
|
-
const tools = nextStep.tools?.map((tool) => this.registry.get(tool)).filter(isNonNullable) ?? [];
|
|
188
|
-
const messages = await session.run({
|
|
189
|
-
systemPrompt: SYSTEM_PROMPT,
|
|
190
|
-
history: [...state.history, ...inputMessages],
|
|
191
|
-
tools: [...tools, report],
|
|
192
|
-
artifacts: [],
|
|
193
|
-
client: options.aiClient,
|
|
194
|
-
prompt: nextStep.instructions,
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
const { messages: trimmedHistory, call: lastBlock } = popLastToolCall(messages);
|
|
198
|
-
if (!lastBlock) {
|
|
199
|
-
// TODO(dmaretskyi): Handle this with grace.
|
|
200
|
-
throw new Error('Agent did not call the report tool');
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const { status, comment } = ReportSchema.pipe(Schema.decodeUnknownSync)(lastBlock.input);
|
|
204
|
-
|
|
205
|
-
return {
|
|
206
|
-
history: [...state.history, ...inputMessages, ...trimmedHistory],
|
|
207
|
-
trace: [
|
|
208
|
-
...state.trace,
|
|
209
|
-
{
|
|
210
|
-
stepId: nextStep.id,
|
|
211
|
-
status,
|
|
212
|
-
comment,
|
|
213
|
-
},
|
|
214
|
-
],
|
|
215
|
-
state: Match.value(status).pipe(
|
|
216
|
-
Match.withReturnType<BlueprintMachineState['state']>(),
|
|
217
|
-
Match.when('done', () => (onLastStep ? 'done' : 'working')),
|
|
218
|
-
Match.when('skipped', () => (onLastStep ? 'done' : 'working')),
|
|
219
|
-
Match.when('bailed', () => 'bail'),
|
|
220
|
-
Match.exhaustive,
|
|
221
|
-
),
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const taggedDataBlock = (tag: string, data: unknown): MessageContentBlock => {
|
|
227
|
-
return {
|
|
228
|
-
type: 'text',
|
|
229
|
-
text: `<${tag}>\n${JSON.stringify(data, null, 2)}\n</${tag}>`,
|
|
230
|
-
} satisfies MessageContentBlock;
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
const popLastToolCall = (messages: Message[]): { messages: Message[]; call?: ToolUseContentBlock } => {
|
|
234
|
-
const lastBlock = messages.at(-1)?.content.at(-1);
|
|
235
|
-
if (lastBlock?.type !== 'tool_use') {
|
|
236
|
-
return { messages };
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const trimmedHistory = [
|
|
240
|
-
...messages.slice(0, -1),
|
|
241
|
-
{
|
|
242
|
-
...messages.at(-1)!,
|
|
243
|
-
content: [...messages.at(-1)!.content.slice(0, -1)],
|
|
244
|
-
} satisfies Message,
|
|
245
|
-
];
|
|
246
|
-
|
|
247
|
-
return {
|
|
248
|
-
messages: trimmedHistory,
|
|
249
|
-
call: lastBlock,
|
|
250
|
-
};
|
|
251
|
-
};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { Obj } from '@dxos/echo';
|
|
6
|
-
import { DataType } from '@dxos/schema';
|
|
7
|
-
|
|
8
|
-
// TODO(burdon): Convert to queue.
|
|
9
|
-
export const TEST_EMAILS: DataType.Message[] = [
|
|
10
|
-
Obj.make(DataType.Message, {
|
|
11
|
-
properties: {
|
|
12
|
-
subject: 'Introduction email',
|
|
13
|
-
},
|
|
14
|
-
sender: {
|
|
15
|
-
email: 'alice@example.com',
|
|
16
|
-
},
|
|
17
|
-
blocks: [
|
|
18
|
-
{
|
|
19
|
-
type: 'text',
|
|
20
|
-
text: "Hi there! I came across your work and would love to connect. I'm working on some interesting projects in the decentralized space and think there could be good collaboration opportunities.",
|
|
21
|
-
},
|
|
22
|
-
],
|
|
23
|
-
created: new Date().toISOString(),
|
|
24
|
-
}),
|
|
25
|
-
Obj.make(DataType.Message, {
|
|
26
|
-
properties: {
|
|
27
|
-
subject: 'Question about integration',
|
|
28
|
-
},
|
|
29
|
-
sender: {
|
|
30
|
-
email: 'bob@example.com',
|
|
31
|
-
},
|
|
32
|
-
blocks: [
|
|
33
|
-
{
|
|
34
|
-
type: 'text',
|
|
35
|
-
text: "Hello, I was wondering if your system supports integration with external APIs? We have some custom services we'd like to connect. Could you explain the process?",
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
created: new Date().toISOString(),
|
|
39
|
-
}),
|
|
40
|
-
Obj.make(DataType.Message, {
|
|
41
|
-
properties: {
|
|
42
|
-
subject: 'MAKE MONEY FAST!!!',
|
|
43
|
-
},
|
|
44
|
-
sender: {
|
|
45
|
-
email: 'spammer123@sketchy.com',
|
|
46
|
-
},
|
|
47
|
-
blocks: [
|
|
48
|
-
{
|
|
49
|
-
type: 'text',
|
|
50
|
-
text: 'CONGRATULATIONS!!! You have been selected to receive $10 MILLION dollars! Just send us your bank details and social security number to claim your prize NOW!!!',
|
|
51
|
-
},
|
|
52
|
-
],
|
|
53
|
-
created: new Date().toISOString(),
|
|
54
|
-
}),
|
|
55
|
-
];
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { describe, test, beforeAll } from 'vitest';
|
|
6
|
-
|
|
7
|
-
import { EdgeAiServiceClient } from '@dxos/ai';
|
|
8
|
-
import { AI_SERVICE_ENDPOINT } from '@dxos/ai/testing';
|
|
9
|
-
import { FunctionExecutor, ServiceContainer } from '@dxos/functions';
|
|
10
|
-
import { log } from '@dxos/log';
|
|
11
|
-
import { createTestData } from '@dxos/schema/testing';
|
|
12
|
-
import { range } from '@dxos/util';
|
|
13
|
-
|
|
14
|
-
import { extractionAnthropicFn } from './extraction-llm-function';
|
|
15
|
-
import { processTranscriptMessage } from '../extraction';
|
|
16
|
-
|
|
17
|
-
describe.skip('LLM EntityExtraction', () => {
|
|
18
|
-
let executor: FunctionExecutor;
|
|
19
|
-
|
|
20
|
-
beforeAll(async () => {
|
|
21
|
-
executor = new FunctionExecutor(
|
|
22
|
-
new ServiceContainer().setServices({
|
|
23
|
-
ai: {
|
|
24
|
-
client: new EdgeAiServiceClient({
|
|
25
|
-
endpoint: AI_SERVICE_ENDPOINT.REMOTE,
|
|
26
|
-
defaultGenerationOptions: {
|
|
27
|
-
// model: '@anthropic/claude-sonnet-4-20250514',
|
|
28
|
-
model: '@anthropic/claude-3-5-haiku-20241022',
|
|
29
|
-
},
|
|
30
|
-
}),
|
|
31
|
-
},
|
|
32
|
-
}),
|
|
33
|
-
);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test('should process a transcript block', async () => {
|
|
37
|
-
const { transcriptMessages, documents, contacts } = createTestData();
|
|
38
|
-
log.info('context', { documents, contacts });
|
|
39
|
-
|
|
40
|
-
for (const message of transcriptMessages.slice(0, 1)) {
|
|
41
|
-
log.info('input', message);
|
|
42
|
-
const { message: enhancedMessage } = await processTranscriptMessage({
|
|
43
|
-
input: {
|
|
44
|
-
message,
|
|
45
|
-
objects: [...documents, ...Object.values(contacts)],
|
|
46
|
-
},
|
|
47
|
-
function: extractionAnthropicFn,
|
|
48
|
-
executor,
|
|
49
|
-
});
|
|
50
|
-
log.info('output', enhancedMessage);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('computational irreducibility', async () => {
|
|
55
|
-
const { transcriptWoflram, documents, contacts } = createTestData();
|
|
56
|
-
|
|
57
|
-
log.info('context', { documents, contacts });
|
|
58
|
-
const message = transcriptWoflram[0];
|
|
59
|
-
log.info('input', message);
|
|
60
|
-
|
|
61
|
-
await Promise.all(
|
|
62
|
-
range(10).map(async () => {
|
|
63
|
-
const { message: enhancedMessage, timeElapsed } = await processTranscriptMessage({
|
|
64
|
-
input: {
|
|
65
|
-
message,
|
|
66
|
-
objects: [...documents, ...Object.values(contacts)],
|
|
67
|
-
},
|
|
68
|
-
function: extractionAnthropicFn,
|
|
69
|
-
executor,
|
|
70
|
-
});
|
|
71
|
-
log.info('output', { message: enhancedMessage.blocks[0], timeElapsed });
|
|
72
|
-
}),
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test('org and document linking', async () => {
|
|
77
|
-
const { transcriptJosiah, documents, contacts, organizations } = createTestData();
|
|
78
|
-
|
|
79
|
-
log.info('context', { contacts, organizations, documents });
|
|
80
|
-
|
|
81
|
-
for (const message of transcriptJosiah) {
|
|
82
|
-
log.info('input', message);
|
|
83
|
-
|
|
84
|
-
const { message: enhancedMessage } = await processTranscriptMessage({
|
|
85
|
-
input: {
|
|
86
|
-
message,
|
|
87
|
-
objects: [...documents, ...Object.values(contacts), ...Object.values(organizations)],
|
|
88
|
-
},
|
|
89
|
-
function: extractionAnthropicFn,
|
|
90
|
-
executor,
|
|
91
|
-
});
|
|
92
|
-
log.info('output', enhancedMessage);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
});
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { Message } from '@dxos/ai';
|
|
6
|
-
import { Obj } from '@dxos/echo';
|
|
7
|
-
import { create } from '@dxos/echo-schema';
|
|
8
|
-
import { AiService, defineFunction, type FunctionDefinition } from '@dxos/functions';
|
|
9
|
-
import { DataType } from '@dxos/schema';
|
|
10
|
-
|
|
11
|
-
import PROMPT from './instructions.tpl?raw';
|
|
12
|
-
import { AISession } from '../../session';
|
|
13
|
-
import { ExtractionInput, ExtractionOutput } from '../extraction';
|
|
14
|
-
import { insertReferences, ReferencedQuotes } from '../quotes';
|
|
15
|
-
|
|
16
|
-
export const extractionAnthropicFn: FunctionDefinition<ExtractionInput, ExtractionOutput> = defineFunction({
|
|
17
|
-
description: 'Extract entities from the transcript message and add them to the message.',
|
|
18
|
-
inputSchema: ExtractionInput,
|
|
19
|
-
outputSchema: ExtractionOutput,
|
|
20
|
-
handler: async ({ data: { message, objects }, context }) => {
|
|
21
|
-
const startTime = performance.now();
|
|
22
|
-
const ai = context.getService(AiService);
|
|
23
|
-
const session = new AISession({ operationModel: 'configured' });
|
|
24
|
-
const result = await session.runStructured(ReferencedQuotes, {
|
|
25
|
-
generationOptions: {
|
|
26
|
-
model: '@anthropic/claude-3-5-haiku-20241022',
|
|
27
|
-
},
|
|
28
|
-
client: ai.client,
|
|
29
|
-
systemPrompt: PROMPT,
|
|
30
|
-
history: [
|
|
31
|
-
Obj.make(Message, {
|
|
32
|
-
role: 'user',
|
|
33
|
-
content: [
|
|
34
|
-
{
|
|
35
|
-
type: 'text',
|
|
36
|
-
text: `<context>${JSON.stringify(objects)}</context>`,
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
type: 'text',
|
|
40
|
-
text: `<transcript>${JSON.stringify(message.blocks)}</transcript>`,
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
}),
|
|
44
|
-
],
|
|
45
|
-
artifacts: [],
|
|
46
|
-
prompt: '',
|
|
47
|
-
tools: [],
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
message: create(DataType.Message, {
|
|
52
|
-
...message,
|
|
53
|
-
blocks: message.blocks.map((block, i) =>
|
|
54
|
-
block.type !== 'transcription'
|
|
55
|
-
? block
|
|
56
|
-
: {
|
|
57
|
-
...block,
|
|
58
|
-
text: insertReferences(block.text, result),
|
|
59
|
-
},
|
|
60
|
-
),
|
|
61
|
-
}),
|
|
62
|
-
timeElapsed: performance.now() - startTime,
|
|
63
|
-
};
|
|
64
|
-
},
|
|
65
|
-
});
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { describe, test, beforeAll } from 'vitest';
|
|
6
|
-
|
|
7
|
-
import { type EchoDatabase } from '@dxos/echo-db';
|
|
8
|
-
import { EchoTestBuilder } from '@dxos/echo-db/testing';
|
|
9
|
-
import { FunctionExecutor, ServiceContainer } from '@dxos/functions';
|
|
10
|
-
import { log } from '@dxos/log';
|
|
11
|
-
import { DataType } from '@dxos/schema';
|
|
12
|
-
import { createTestData, Testing } from '@dxos/schema/testing';
|
|
13
|
-
import { range } from '@dxos/util';
|
|
14
|
-
|
|
15
|
-
import { extractionNerFn } from './extraction-ner-function';
|
|
16
|
-
import { processTranscriptMessage } from '../extraction';
|
|
17
|
-
|
|
18
|
-
describe.skip('NER EntityExtraction', () => {
|
|
19
|
-
let builder: EchoTestBuilder;
|
|
20
|
-
let db: EchoDatabase;
|
|
21
|
-
let executor: FunctionExecutor;
|
|
22
|
-
let testData: {
|
|
23
|
-
transcriptJosiah: DataType.Message[];
|
|
24
|
-
transcriptWoflram: DataType.Message[];
|
|
25
|
-
transcriptMessages: DataType.Message[];
|
|
26
|
-
documents: Testing.DocumentType[];
|
|
27
|
-
contacts: Record<string, DataType.Person>;
|
|
28
|
-
organizations: Record<string, DataType.Organization>;
|
|
29
|
-
};
|
|
30
|
-
const TYPES = [DataType.Organization, DataType.Person, Testing.Contact, Testing.DocumentType];
|
|
31
|
-
|
|
32
|
-
beforeAll(async () => {
|
|
33
|
-
// TODO(dmaretskyi): Helper to scaffold this from a config.
|
|
34
|
-
builder = await new EchoTestBuilder().open();
|
|
35
|
-
const { db: db1 } = await builder.createDatabase({ indexing: { vector: true } });
|
|
36
|
-
db = db1;
|
|
37
|
-
db.graph.schemaRegistry.addSchema(TYPES);
|
|
38
|
-
const data = createTestData();
|
|
39
|
-
testData = {
|
|
40
|
-
transcriptJosiah: data.transcriptJosiah,
|
|
41
|
-
transcriptWoflram: data.transcriptWoflram,
|
|
42
|
-
transcriptMessages: data.transcriptMessages,
|
|
43
|
-
documents: data.documents.map((document) => db.add(document)),
|
|
44
|
-
contacts: Object.fromEntries(Object.entries(data.contacts).map(([key, value]) => [key, db.add(value)])),
|
|
45
|
-
organizations: Object.fromEntries(Object.entries(data.organizations).map(([key, value]) => [key, db.add(value)])),
|
|
46
|
-
};
|
|
47
|
-
await db.flush();
|
|
48
|
-
|
|
49
|
-
executor = new FunctionExecutor(
|
|
50
|
-
new ServiceContainer().setServices({
|
|
51
|
-
database: { db },
|
|
52
|
-
}),
|
|
53
|
-
);
|
|
54
|
-
}, 30_000);
|
|
55
|
-
|
|
56
|
-
test('should process a transcript block', async () => {
|
|
57
|
-
const { transcriptMessages, documents, contacts } = testData;
|
|
58
|
-
log.info('context', { documents, contacts });
|
|
59
|
-
|
|
60
|
-
for (const message of transcriptMessages) {
|
|
61
|
-
log.info('input', message);
|
|
62
|
-
const { message: enhancedMessage } = await processTranscriptMessage({
|
|
63
|
-
input: {
|
|
64
|
-
message,
|
|
65
|
-
objects: [...documents, ...Object.values(contacts)],
|
|
66
|
-
},
|
|
67
|
-
function: extractionNerFn,
|
|
68
|
-
executor,
|
|
69
|
-
});
|
|
70
|
-
log.info('output', enhancedMessage);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('computational irreducibility', async () => {
|
|
75
|
-
const { transcriptWoflram, documents, contacts } = testData;
|
|
76
|
-
|
|
77
|
-
log.info('context', { documents, contacts });
|
|
78
|
-
const message = transcriptWoflram[0];
|
|
79
|
-
log.info('input', message);
|
|
80
|
-
|
|
81
|
-
await Promise.all(
|
|
82
|
-
range(10).map(async () => {
|
|
83
|
-
const { message: enhancedMessage, timeElapsed } = await processTranscriptMessage({
|
|
84
|
-
input: {
|
|
85
|
-
message,
|
|
86
|
-
objects: [...documents, ...Object.values(contacts)],
|
|
87
|
-
},
|
|
88
|
-
function: extractionNerFn,
|
|
89
|
-
executor,
|
|
90
|
-
});
|
|
91
|
-
log.info('output', { message: enhancedMessage.blocks[0], timeElapsed });
|
|
92
|
-
}),
|
|
93
|
-
);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test('org and document linking', async () => {
|
|
97
|
-
const { transcriptJosiah, documents, contacts, organizations } = testData;
|
|
98
|
-
|
|
99
|
-
log.info('context', { contacts, organizations, documents });
|
|
100
|
-
|
|
101
|
-
for (const message of transcriptJosiah) {
|
|
102
|
-
log.info('input', message);
|
|
103
|
-
|
|
104
|
-
const { message: enhancedMessage } = await processTranscriptMessage({
|
|
105
|
-
input: {
|
|
106
|
-
message,
|
|
107
|
-
objects: [...documents, ...Object.values(contacts), ...Object.values(organizations)],
|
|
108
|
-
},
|
|
109
|
-
function: extractionNerFn,
|
|
110
|
-
executor,
|
|
111
|
-
});
|
|
112
|
-
log.info('output', enhancedMessage);
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
});
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { asyncTimeout } from '@dxos/async';
|
|
6
|
-
import { create } from '@dxos/echo-schema';
|
|
7
|
-
import { DatabaseService, defineFunction } from '@dxos/functions';
|
|
8
|
-
import { invariant } from '@dxos/invariant';
|
|
9
|
-
import { log } from '@dxos/log';
|
|
10
|
-
import { DataType } from '@dxos/schema';
|
|
11
|
-
|
|
12
|
-
import { extractFullEntities } from './named-entity-recognition';
|
|
13
|
-
import { ExtractionInput, ExtractionOutput } from '../extraction';
|
|
14
|
-
import { findQuotes, insertReferences } from '../quotes';
|
|
15
|
-
|
|
16
|
-
// TODO(mykola): Make it use vector index to query objects and not pass objects as input.
|
|
17
|
-
export const extractionNerFn = defineFunction({
|
|
18
|
-
description: 'Extracts named entities from a text',
|
|
19
|
-
inputSchema: ExtractionInput,
|
|
20
|
-
outputSchema: ExtractionOutput,
|
|
21
|
-
handler: async ({ data: { message, options }, context }) => {
|
|
22
|
-
log.info('input', { message, options });
|
|
23
|
-
const startTime = performance.now();
|
|
24
|
-
const { db } = context.getService(DatabaseService);
|
|
25
|
-
|
|
26
|
-
const entitiesPromise = Promise.all(
|
|
27
|
-
message.blocks.map(async (block) => {
|
|
28
|
-
invariant(block.type === 'transcription' || block.type === 'text', 'Block must have text');
|
|
29
|
-
return extractFullEntities(block.text);
|
|
30
|
-
}),
|
|
31
|
-
).then((entities) => entities.flat());
|
|
32
|
-
const entities = options?.timeout ? await asyncTimeout(entitiesPromise, options.timeout) : await entitiesPromise;
|
|
33
|
-
log.info('entities', { entities });
|
|
34
|
-
const quoteReferences = await findQuotes(
|
|
35
|
-
entities.map((entity) => entity.word),
|
|
36
|
-
db,
|
|
37
|
-
);
|
|
38
|
-
const blocksWithReferences = message.blocks.map((block, i) => {
|
|
39
|
-
invariant(block.type === 'transcription' || block.type === 'text', 'Block must have text');
|
|
40
|
-
return { ...block, text: insertReferences(block.text, quoteReferences) };
|
|
41
|
-
});
|
|
42
|
-
const messageWithReferences = create(DataType.Message, {
|
|
43
|
-
...message,
|
|
44
|
-
blocks: blocksWithReferences,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
log.info('output', { messageWithReferences });
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
message: messageWithReferences,
|
|
51
|
-
timeElapsed: performance.now() - startTime,
|
|
52
|
-
};
|
|
53
|
-
},
|
|
54
|
-
});
|