@dxos/assistant 0.8.4-main.fffef41 → 0.8.4-staging.60fe92afc8
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/LICENSE +102 -5
- package/README.md +2 -1
- package/dist/lib/{browser → neutral}/extraction/index.mjs +42 -59
- package/dist/lib/neutral/extraction/index.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +1886 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +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.map +1 -1
- package/dist/types/src/extraction/extraction.d.ts +1649 -317
- 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 +2 -2
- package/dist/types/src/extraction/quotes.d.ts.map +1 -1
- package/dist/types/src/functions/services.d.ts +14 -16
- package/dist/types/src/functions/services.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -5
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/request/AiRequest.d.ts +308 -0
- package/dist/types/src/request/AiRequest.d.ts.map +1 -0
- package/dist/types/src/{session → request}/artifact-diff.d.ts +4 -4
- package/dist/types/src/request/artifact-diff.d.ts.map +1 -0
- package/dist/types/src/request/format.d.ts +15 -0
- package/dist/types/src/request/format.d.ts.map +1 -0
- package/dist/types/src/request/index.d.ts +4 -0
- package/dist/types/src/request/index.d.ts.map +1 -0
- package/dist/types/src/{session → request}/observer.d.ts +4 -3
- package/dist/types/src/request/observer.d.ts.map +1 -0
- package/dist/types/src/{session → request}/version-pin.d.ts +4 -4
- package/dist/types/src/request/version-pin.d.ts.map +1 -0
- package/dist/types/src/session/AiContext.d.ts +178 -0
- package/dist/types/src/session/AiContext.d.ts.map +1 -0
- package/dist/types/src/session/AiContext.test.d.ts +2 -0
- package/dist/types/src/session/AiContext.test.d.ts.map +1 -0
- package/dist/types/src/session/AiSession.d.ts +79 -0
- package/dist/types/src/session/AiSession.d.ts.map +1 -0
- package/dist/types/src/session/AiSession.test.d.ts +2 -0
- package/dist/types/src/session/AiSession.test.d.ts.map +1 -0
- package/dist/types/src/session/SessionLink.d.ts +17 -0
- package/dist/types/src/session/SessionLink.d.ts.map +1 -0
- package/dist/types/src/session/SessionLoader.d.ts +15 -0
- package/dist/types/src/session/SessionLoader.d.ts.map +1 -0
- package/dist/types/src/session/SessionLoader.test.d.ts +2 -0
- package/dist/types/src/session/SessionLoader.test.d.ts.map +1 -0
- package/dist/types/src/session/index.d.ts +4 -5
- package/dist/types/src/session/index.d.ts.map +1 -1
- package/dist/types/src/session/toolkit.d.ts +10 -9
- package/dist/types/src/session/toolkit.d.ts.map +1 -1
- package/dist/types/src/templates/system.d.ts +12 -3
- package/dist/types/src/templates/system.d.ts.map +1 -1
- package/dist/types/src/util/artifact.d.ts +18 -0
- package/dist/types/src/util/artifact.d.ts.map +1 -0
- package/dist/types/src/{diff.d.ts → util/diff.d.ts} +4 -2
- package/dist/types/src/util/diff.d.ts.map +1 -0
- package/dist/types/src/{diff.test.d.ts.map → util/diff.test.d.ts.map} +1 -1
- package/dist/types/src/util/error-handling.d.ts.map +1 -0
- package/dist/types/src/{errors.d.ts → util/errors.d.ts} +24 -28
- package/dist/types/src/util/errors.d.ts.map +1 -0
- package/dist/types/src/{execution-graph.d.ts → util/execution-graph.d.ts} +2 -2
- package/dist/types/src/util/execution-graph.d.ts.map +1 -0
- package/dist/types/src/util/execution-graph.test.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +7 -0
- package/dist/types/src/util/index.d.ts.map +1 -0
- package/dist/types/src/util/tracing.d.ts +296 -0
- package/dist/types/src/util/tracing.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +36 -44
- package/src/extraction/extraction-ner-function/index.ts +0 -1
- package/src/extraction/extraction.ts +47 -18
- package/src/extraction/index.ts +0 -1
- package/src/extraction/quotes.test.ts +2 -2
- package/src/extraction/quotes.ts +6 -8
- package/src/functions/services.ts +129 -63
- package/src/index.ts +2 -5
- package/src/request/AiRequest.ts +387 -0
- package/src/{session → request}/artifact-diff.ts +4 -4
- package/src/{session → request}/format.ts +28 -25
- package/src/request/index.ts +8 -0
- package/src/{session → request}/observer.ts +4 -1
- package/src/{session → request}/version-pin.ts +6 -5
- package/src/session/AiContext.test.ts +49 -0
- package/src/session/AiContext.ts +420 -0
- package/src/session/AiSession.test.ts +111 -0
- package/src/session/AiSession.ts +328 -0
- package/src/session/SessionLink.ts +23 -0
- package/src/session/SessionLoader.test.ts +115 -0
- package/src/session/SessionLoader.ts +55 -0
- package/src/session/index.ts +4 -5
- package/src/session/toolkit.ts +27 -28
- package/src/templates/instructions/format.tpl +0 -4
- package/src/templates/instructions/system.tpl +50 -2
- package/src/templates/system.ts +7 -6
- package/src/util/artifact.ts +96 -0
- package/src/util/diff.test.ts +74 -0
- package/src/{diff.ts → util/diff.ts} +14 -5
- package/src/{session → util}/error-handling.ts +3 -2
- package/src/util/errors.ts +15 -0
- package/src/{execution-graph.test.ts → util/execution-graph.test.ts} +4 -4
- package/src/{execution-graph.ts → util/execution-graph.ts} +30 -19
- package/src/util/index.ts +10 -0
- package/src/util/tracing.ts +60 -0
- package/dist/lib/browser/extraction/index.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -1290
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
- package/dist/lib/node-esm/extraction/index.mjs +0 -226
- package/dist/lib/node-esm/extraction/index.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -1291
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/types/src/conversation/context.d.ts +0 -103
- package/dist/types/src/conversation/context.d.ts.map +0 -1
- package/dist/types/src/conversation/conversation.d.ts +0 -41
- package/dist/types/src/conversation/conversation.d.ts.map +0 -1
- package/dist/types/src/conversation/index.d.ts +0 -3
- package/dist/types/src/conversation/index.d.ts.map +0 -1
- package/dist/types/src/diff.d.ts.map +0 -1
- package/dist/types/src/errors.d.ts.map +0 -1
- package/dist/types/src/execution-graph.d.ts.map +0 -1
- package/dist/types/src/execution-graph.test.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 -345
- 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/session/GenericToolkit.d.ts +0 -84
- package/dist/types/src/session/GenericToolkit.d.ts.map +0 -1
- package/dist/types/src/session/artifact-diff.d.ts.map +0 -1
- package/dist/types/src/session/error-handling.d.ts.map +0 -1
- package/dist/types/src/session/format.d.ts +0 -12
- package/dist/types/src/session/format.d.ts.map +0 -1
- package/dist/types/src/session/format.test.d.ts +0 -2
- package/dist/types/src/session/format.test.d.ts.map +0 -1
- package/dist/types/src/session/observer.d.ts.map +0 -1
- package/dist/types/src/session/session.d.ts +0 -51
- 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.d.ts.map +0 -1
- package/dist/types/src/types/artifact.d.ts +0 -20
- package/dist/types/src/types/artifact.d.ts.map +0 -1
- package/dist/types/src/types/index.d.ts +0 -2
- package/dist/types/src/types/index.d.ts.map +0 -1
- package/src/conversation/context.ts +0 -186
- package/src/conversation/conversation.ts +0 -128
- package/src/conversation/index.ts +0 -6
- package/src/diff.test.ts +0 -43
- package/src/errors.ts +0 -15
- package/src/extraction/extraction-llm-function/extraction-llm-function.test.ts +0 -84
- package/src/extraction/extraction-llm-function/extraction-llm-function.ts +0 -62
- package/src/extraction/extraction-llm-function/index.ts +0 -5
- package/src/extraction/extraction-ner-function/extraction-ner-function.test.ts +0 -116
- package/src/extraction/extraction-ner-function/extraction-ner-function.ts +0 -56
- package/src/session/GenericToolkit.ts +0 -130
- package/src/session/format.test.ts +0 -61
- package/src/session/session.conversations.json +0 -1
- package/src/session/session.test.ts +0 -149
- package/src/session/session.ts +0 -213
- package/src/types/artifact.ts +0 -71
- package/src/types/index.ts +0 -5
- /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
- /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs.map +0 -0
- /package/dist/types/src/{diff.test.d.ts → util/diff.test.d.ts} +0 -0
- /package/dist/types/src/{session → util}/error-handling.d.ts +0 -0
- /package/dist/types/src/{execution-graph.test.d.ts → util/execution-graph.test.d.ts} +0 -0
package/src/templates/system.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import defaultsDeep from 'lodash.defaultsdeep';
|
|
6
6
|
|
|
7
7
|
import { type ModelCapabilities } from '@dxos/ai';
|
|
8
|
-
import { Template } from '@dxos/
|
|
8
|
+
import { Template } from '@dxos/compute';
|
|
9
9
|
|
|
10
10
|
import FORMAT from './instructions/format.tpl?raw';
|
|
11
11
|
import SYSTEM from './instructions/system.tpl?raw';
|
|
@@ -29,13 +29,14 @@ export const createSystemPrompt = (options: Partial<SystemPromptOptions> = {}) =
|
|
|
29
29
|
}),
|
|
30
30
|
);
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* NOTE: We are forbidden from accessing randomness at model level in cloudflare, so we have to have pre-generated ids.
|
|
34
|
+
*/
|
|
35
|
+
const SYSTEM_ID = '01K2J2FZWH39F55CS7B26GP1Q3';
|
|
36
|
+
|
|
32
37
|
export const templates = {
|
|
33
|
-
/** Editable system prompt.*/
|
|
34
38
|
system: Template.make({
|
|
35
|
-
|
|
36
|
-
* NOTE: We are forbidden from accessing randomness at model level in cloudflare, so we have to have pre-generated ids.
|
|
37
|
-
*/
|
|
38
|
-
id: '01K2J2FZWH39F55CS7B26GP1Q3',
|
|
39
|
+
id: SYSTEM_ID,
|
|
39
40
|
source: SYSTEM,
|
|
40
41
|
}),
|
|
41
42
|
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
7
|
+
|
|
8
|
+
import { Database, type Err, Obj, Ref, type Type } from '@dxos/echo';
|
|
9
|
+
import { EncodedReference } from '@dxos/echo-protocol';
|
|
10
|
+
import { EID, EntityId, SpaceId } from '@dxos/keys';
|
|
11
|
+
import { trim } from '@dxos/util';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated
|
|
15
|
+
*/
|
|
16
|
+
export const createArtifactElement = (id: EntityId) => `<artifact id=${id} />`;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A model-friendly way to reference an object.
|
|
20
|
+
* Supports vairous formats that will be normalized to a DXN.
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
const ArtifactURI: Schema.Schema<string> & {
|
|
25
|
+
toEchoURI: (reference: ArtifactURI, owningSpaceId?: SpaceId) => EID.EID;
|
|
26
|
+
resolve: <S extends Type.AnyEntity>(
|
|
27
|
+
schema: S,
|
|
28
|
+
ref: ArtifactURI,
|
|
29
|
+
) => Effect.Effect<Type.InstanceType<S>, Err.EntityNotFoundError, Database.Service>;
|
|
30
|
+
} = class extends Schema.String.annotations({
|
|
31
|
+
// TODO(dmaretskyi): This section gets overriden.
|
|
32
|
+
description: trim`
|
|
33
|
+
The URI of the referenced object. Protocols accepted:
|
|
34
|
+
- echo://01KG7R1ZXWFMWQ4DA1Q6TN1DG4.
|
|
35
|
+
- space ID, object ID tuple (spaceID:objectID)
|
|
36
|
+
- Only object ID that is assumed to be in the current space (01KG7R1ZXWFMWQ4DA1Q6TN1DG4)
|
|
37
|
+
- dxn:org.dxos.type.calendar:0.1.0 -- named entity from the registry. Absoutely make sure it actually exists in the registry.
|
|
38
|
+
|
|
39
|
+
URIs can be prepended with an @ symbol for compatibility with in-text references.
|
|
40
|
+
`,
|
|
41
|
+
examples: [
|
|
42
|
+
'echo://01KG7R1ZXWFMWQ4DA1Q6TN1DG4',
|
|
43
|
+
'@echo://01KG7R1ZXWFMWQ4DA1Q6TN1DG4',
|
|
44
|
+
'BM3FSHFOMJCHCG5QW7JTVKGYABD2GAA7G:01KG7R1ZXWFMWQ4DA1Q6TN1DG4',
|
|
45
|
+
'01KG7R1ZXWFMWQ4DA1Q6TN1DG4',
|
|
46
|
+
'dxn:org.dxos.type.calendar:0.1.0',
|
|
47
|
+
'@dxn:org.dxos.type.calendar:0.1.0',
|
|
48
|
+
],
|
|
49
|
+
}) {
|
|
50
|
+
static toEchoURI(reference: ArtifactURI, owningSpaceId?: SpaceId): EID.EID {
|
|
51
|
+
// Allow @ prefix for compatibility with in-text references.
|
|
52
|
+
const stripped = reference.startsWith('@') ? reference.slice(1) : reference;
|
|
53
|
+
if (stripped.startsWith('echo:') || stripped.startsWith('dxn:')) {
|
|
54
|
+
return EID.parse(stripped);
|
|
55
|
+
} else if (stripped.includes(':')) {
|
|
56
|
+
const [spaceId, objectId] = stripped.split(':');
|
|
57
|
+
if (!SpaceId.isValid(spaceId) || !EntityId.isValid(objectId)) {
|
|
58
|
+
throw new Error(`Unable to parse object reference: ${reference}`);
|
|
59
|
+
}
|
|
60
|
+
// This is a workaround because the current Filter API doesn't work with fully qualified Echo URIs.
|
|
61
|
+
// We check if the space ID is the same as the owning space and then use LOCAL_SPACE_TAG for local references.
|
|
62
|
+
// TODO(dmaretskyi): Fix this in the Echo and Filter API to properly handle fully qualified URIs.
|
|
63
|
+
return spaceId === owningSpaceId
|
|
64
|
+
? EID.make({ entityId: objectId })
|
|
65
|
+
: EID.make({ spaceId: spaceId, entityId: objectId });
|
|
66
|
+
} else if (EntityId.isValid(stripped)) {
|
|
67
|
+
return EID.make({ entityId: stripped });
|
|
68
|
+
} else {
|
|
69
|
+
throw new Error(`Unable to parse object reference: ${reference}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Resolves an artifact ID to an object.
|
|
75
|
+
*/
|
|
76
|
+
static resolve<S extends Type.AnyEntity>(
|
|
77
|
+
schema: S,
|
|
78
|
+
ref: ArtifactURI,
|
|
79
|
+
): Effect.Effect<Type.InstanceType<S>, Err.EntityNotFoundError, Database.Service> {
|
|
80
|
+
const uri = ArtifactURI.toEchoURI(ref);
|
|
81
|
+
return Database.resolve(Ref.fromURI(uri), schema);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
type ArtifactURI = Schema.Schema.Type<typeof ArtifactURI>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Schema that decodes ECHO reference object from an LLM-friendly input.
|
|
89
|
+
*/
|
|
90
|
+
export const RefFromLLM = Schema.transform(ArtifactURI, Ref.Ref(Obj.Unknown), {
|
|
91
|
+
decode: (fromA, fromI) => EncodedReference.fromURI(ArtifactURI.toEchoURI(fromA)),
|
|
92
|
+
encode: (toI, toA) => EncodedReference.toURI(toI),
|
|
93
|
+
strict: false,
|
|
94
|
+
}).annotations({
|
|
95
|
+
description: ArtifactURI.ast.annotations.description as string,
|
|
96
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { createDocAccessor } from '@dxos/echo-client';
|
|
8
|
+
import { EchoTestBuilder } from '@dxos/echo-client/testing';
|
|
9
|
+
import { Text } from '@dxos/schema';
|
|
10
|
+
import { trim } from '@dxos/util';
|
|
11
|
+
|
|
12
|
+
import { applyDiffs } from './diff';
|
|
13
|
+
|
|
14
|
+
describe('diff', () => {
|
|
15
|
+
let builder: EchoTestBuilder;
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
builder = await new EchoTestBuilder().open();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
await builder.close();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should apply diffs', async () => {
|
|
25
|
+
const { db } = await builder.createDatabase({ types: [Text.Text] });
|
|
26
|
+
|
|
27
|
+
const document = trim`
|
|
28
|
+
# Hello World
|
|
29
|
+
There'z a typo in this sentence.
|
|
30
|
+
And another oon here.
|
|
31
|
+
But not this one.
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const text = db.add(Text.make({ content: document }));
|
|
35
|
+
const accessor = createDocAccessor(text, ['content']);
|
|
36
|
+
const result = applyDiffs(accessor, [
|
|
37
|
+
`- There'z a typo in this sentence.`,
|
|
38
|
+
`+ There is a typo in this sentence.`,
|
|
39
|
+
`- And another oon here.`,
|
|
40
|
+
`+ And another one here.`,
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
expect(result).toBe(trim`
|
|
44
|
+
# Hello World
|
|
45
|
+
There is a typo in this sentence.
|
|
46
|
+
And another one here.
|
|
47
|
+
But not this one.
|
|
48
|
+
`);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should apply diffs that append content at the end', async () => {
|
|
52
|
+
const { db } = await builder.createDatabase({ types: [Text.Text] });
|
|
53
|
+
|
|
54
|
+
const document = '# Shopping list';
|
|
55
|
+
|
|
56
|
+
const text = db.add(Text.make({ content: document }));
|
|
57
|
+
const accessor = createDocAccessor(text, ['content']);
|
|
58
|
+
const result = applyDiffs(accessor, ['- # Shopping list', '+ # Shopping list\n- Milk']);
|
|
59
|
+
|
|
60
|
+
expect(result).toBe('# Shopping list\n- Milk');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should append text to an empty document', async () => {
|
|
64
|
+
const builder = new EchoTestBuilder();
|
|
65
|
+
const { db, graph } = await builder.createDatabase();
|
|
66
|
+
graph.registry.add([Text.Text]);
|
|
67
|
+
|
|
68
|
+
const text = db.add(Text.make({ content: '' }));
|
|
69
|
+
const accessor = createDocAccessor(text, ['content']);
|
|
70
|
+
const result = applyDiffs(accessor, ['+ # Shopping list']);
|
|
71
|
+
|
|
72
|
+
expect(result).toBe('# Shopping list');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { next as A, type Doc } from '@automerge/automerge';
|
|
6
6
|
|
|
7
|
-
import { DocAccessor, toCursorRange } from '@dxos/echo-
|
|
7
|
+
import { DocAccessor, toCursorRange } from '@dxos/echo-client';
|
|
8
8
|
import { log } from '@dxos/log';
|
|
9
9
|
import { isNonNullable } from '@dxos/util';
|
|
10
10
|
|
|
@@ -47,9 +47,10 @@ export const reduceDiffs = (diffs: readonly string[]): Diff[] => {
|
|
|
47
47
|
}
|
|
48
48
|
return acc;
|
|
49
49
|
}
|
|
50
|
+
default: {
|
|
51
|
+
throw new Error(`Invalid diff format: each line must start with "- " or "+ ", got: ${JSON.stringify(diff)}`);
|
|
52
|
+
}
|
|
50
53
|
}
|
|
51
|
-
|
|
52
|
-
return acc;
|
|
53
54
|
}, []);
|
|
54
55
|
};
|
|
55
56
|
|
|
@@ -65,7 +66,11 @@ export const computeDiffsWithCursors = <T>(accessor: DocAccessor<T>, diffs: read
|
|
|
65
66
|
.filter(isNonNullable);
|
|
66
67
|
};
|
|
67
68
|
|
|
68
|
-
export const applyDiffs = <T>(
|
|
69
|
+
export const applyDiffs = <T>(
|
|
70
|
+
accessor: DocAccessor<T>,
|
|
71
|
+
diffs: readonly string[],
|
|
72
|
+
{ errorOnNotFound = false }: { errorOnNotFound?: boolean } = {},
|
|
73
|
+
): string => {
|
|
69
74
|
for (const diff of reduceDiffs(diffs)) {
|
|
70
75
|
accessor.handle.change((doc: Doc<T>) => {
|
|
71
76
|
const text = DocAccessor.getValue<string>(accessor);
|
|
@@ -75,7 +80,11 @@ export const applyDiffs = <T>(accessor: DocAccessor<T>, diffs: readonly string[]
|
|
|
75
80
|
// NOTE: This only replaces the first match.
|
|
76
81
|
A.splice(doc, accessor.path as A.Prop[], idx, diff.match.length, diff.replace);
|
|
77
82
|
} else {
|
|
78
|
-
|
|
83
|
+
if (errorOnNotFound) {
|
|
84
|
+
throw new Error(`Diff not found: ${diff.match}`);
|
|
85
|
+
} else {
|
|
86
|
+
log.warn('diff not found', diff);
|
|
87
|
+
}
|
|
79
88
|
}
|
|
80
89
|
});
|
|
81
90
|
}
|
|
@@ -7,7 +7,7 @@ import * as HttpClientError from '@effect/platform/HttpClientError';
|
|
|
7
7
|
import * as Effect from 'effect/Effect';
|
|
8
8
|
import * as Schema from 'effect/Schema';
|
|
9
9
|
|
|
10
|
-
import { AiModelError } from '
|
|
10
|
+
import { AiModelError } from './errors';
|
|
11
11
|
|
|
12
12
|
const AnthropicErrorResponse = Schema.Struct({
|
|
13
13
|
type: Schema.Literal('error'),
|
|
@@ -17,7 +17,7 @@ const AnthropicErrorResponse = Schema.Struct({
|
|
|
17
17
|
}),
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
// TODO(dmaretskyi): Needs rework
|
|
20
|
+
// TODO(dmaretskyi): Needs rework.
|
|
21
21
|
export const mapAiError = (err: AiError.AiError): Effect.Effect<AiError.AiError> =>
|
|
22
22
|
Effect.gen(function* () {
|
|
23
23
|
const cause = err.cause;
|
|
@@ -30,6 +30,7 @@ export const mapAiError = (err: AiError.AiError): Effect.Effect<AiError.AiError>
|
|
|
30
30
|
message: body.error.message,
|
|
31
31
|
context: { model: 'anthropic', type: body.error.type },
|
|
32
32
|
});
|
|
33
|
+
|
|
33
34
|
return AiError.UnknownError.make({
|
|
34
35
|
description: body.error.message,
|
|
35
36
|
module: err.module,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { BaseError } from '@dxos/errors';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generic error from AI model.
|
|
9
|
+
*/
|
|
10
|
+
export class AiModelError extends BaseError.extend('AiModelError', 'AI model error') {}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Generic error for AI agent execution.
|
|
14
|
+
*/
|
|
15
|
+
export class AiAssistantError extends BaseError.extend('AiAssistantError', 'AI assistant error') {}
|
|
@@ -6,14 +6,14 @@ import { describe, expect, it } from '@effect/vitest';
|
|
|
6
6
|
|
|
7
7
|
import { AgentStatus } from '@dxos/ai';
|
|
8
8
|
import { Obj } from '@dxos/echo';
|
|
9
|
-
import {
|
|
9
|
+
import { EntityId } from '@dxos/keys';
|
|
10
10
|
import { log } from '@dxos/log';
|
|
11
11
|
import { type ContentBlock, Message } from '@dxos/types';
|
|
12
12
|
|
|
13
13
|
import { ExecutionGraph } from './execution-graph';
|
|
14
14
|
|
|
15
15
|
// Helper function to create valid object IDs for testing.
|
|
16
|
-
const createTestId = () =>
|
|
16
|
+
const createTestId = () => EntityId.random();
|
|
17
17
|
|
|
18
18
|
const SKIP_BLOCKS: ContentBlock.Any['_tag'][] = [];
|
|
19
19
|
|
|
@@ -71,7 +71,7 @@ describe('ExecutionGraph', () => {
|
|
|
71
71
|
blocks: [
|
|
72
72
|
{
|
|
73
73
|
_tag: 'text',
|
|
74
|
-
text: '{"id":"01K6AXZKK79H4E54RKP1YZDARK","@type":"dxn:
|
|
74
|
+
text: '{"id":"01K6AXZKK79H4E54RKP1YZDARK","@type":"dxn:org.dxos.type.organization:0.1.0","@meta":{"keys":[]},"name":"Blue Yard","website":"https://blueyard.com"}',
|
|
75
75
|
},
|
|
76
76
|
],
|
|
77
77
|
properties: {},
|
|
@@ -619,7 +619,7 @@ describe('ExecutionGraph', () => {
|
|
|
619
619
|
{ _tag: 'reasoning', reasoningText: 'I need to think about this' },
|
|
620
620
|
{ _tag: 'toolCall', toolCallId: 'tool1', name: 'analyze', input: '{}', providerExecuted: false },
|
|
621
621
|
{
|
|
622
|
-
_tag: '
|
|
622
|
+
_tag: 'stats',
|
|
623
623
|
message: 'OK',
|
|
624
624
|
duration: 1000,
|
|
625
625
|
toolCalls: 1,
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { AgentStatus } from '@dxos/ai';
|
|
6
|
-
import { Obj, type Ref } from '@dxos/echo';
|
|
6
|
+
import { type Entity, Obj, type Ref } from '@dxos/echo';
|
|
7
7
|
import { MESSAGE_PROPERTY_TOOL_CALL_ID } from '@dxos/functions';
|
|
8
|
-
import { type
|
|
8
|
+
import { EID, type EntityId } from '@dxos/keys';
|
|
9
9
|
import { LogLevel } from '@dxos/log';
|
|
10
10
|
import { ContentBlock, Message } from '@dxos/types';
|
|
11
11
|
import { isNonNullable } from '@dxos/util';
|
|
@@ -40,7 +40,7 @@ enum IconType {
|
|
|
40
40
|
// Interactions.
|
|
41
41
|
USER = 'ph--user--regular',
|
|
42
42
|
USER_INTERACTION = 'ph--user-sound--regular',
|
|
43
|
-
AGENT = 'ph--
|
|
43
|
+
AGENT = 'ph--drone--regular',
|
|
44
44
|
THINKING = 'ph--brain--regular',
|
|
45
45
|
LINK = 'ph--link--regular',
|
|
46
46
|
TOOL = 'ph--wrench--regular',
|
|
@@ -65,7 +65,7 @@ export class ExecutionGraph {
|
|
|
65
65
|
/**
|
|
66
66
|
* Adds events to the graph.
|
|
67
67
|
*/
|
|
68
|
-
addEvents(events:
|
|
68
|
+
addEvents(events: Entity.Unknown[]) {
|
|
69
69
|
const sortedEvents = this.sortObjectsByCreated(events);
|
|
70
70
|
for (const event of sortedEvents) {
|
|
71
71
|
if (Obj.instanceOf(Message.Message, event)) {
|
|
@@ -199,13 +199,19 @@ export class ExecutionGraph {
|
|
|
199
199
|
*/
|
|
200
200
|
private _updatePendingToolResults(toolCallId: string, agentStatusId: string) {
|
|
201
201
|
const toolResultId = this._pendingToolResults.get(toolCallId);
|
|
202
|
-
if (!toolResultId)
|
|
202
|
+
if (!toolResultId) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
203
205
|
|
|
204
206
|
const toolResultCommit = this._commits.find((c) => c.id === toolResultId);
|
|
205
|
-
if (!toolResultCommit)
|
|
207
|
+
if (!toolResultCommit) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
206
210
|
|
|
207
211
|
const toolCallCommitId = this._toolCallCommitIds.get(toolCallId);
|
|
208
|
-
if (!toolCallCommitId)
|
|
212
|
+
if (!toolCallCommitId) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
209
215
|
|
|
210
216
|
// Replace tool call commit with AgentStatus commit.
|
|
211
217
|
const toolCallIndex = toolResultCommit.parents.indexOf(toolCallCommitId);
|
|
@@ -221,7 +227,9 @@ export class ExecutionGraph {
|
|
|
221
227
|
*/
|
|
222
228
|
private _handleLateToolResultUpdate(toolCallId: string, toolResultId: string) {
|
|
223
229
|
const toolCallCommitId = this._toolCallCommitIds.get(toolCallId);
|
|
224
|
-
if (!toolCallCommitId)
|
|
230
|
+
if (!toolCallCommitId) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
225
233
|
|
|
226
234
|
const messageId = toolCallCommitId.split('_toolCall_')[0];
|
|
227
235
|
const toolCallBranch = `${messageId}_${toolCallId}`;
|
|
@@ -242,7 +250,7 @@ export class ExecutionGraph {
|
|
|
242
250
|
/**
|
|
243
251
|
* Gets the branch name for a tool call.
|
|
244
252
|
*/
|
|
245
|
-
private _getToolCallBranch(parentMessage?:
|
|
253
|
+
private _getToolCallBranch(parentMessage?: EntityId, toolCallId?: string): string {
|
|
246
254
|
if (toolCallId) {
|
|
247
255
|
return toolCallId;
|
|
248
256
|
}
|
|
@@ -372,7 +380,9 @@ const createBlockCommit = (
|
|
|
372
380
|
const timestamp = new Date(message.created);
|
|
373
381
|
switch (block._tag) {
|
|
374
382
|
case 'text':
|
|
375
|
-
if (!block.text.trim().length)
|
|
383
|
+
if (!block.text.trim().length) {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
376
386
|
return {
|
|
377
387
|
id: getGenericBlockId(message.id, idx),
|
|
378
388
|
branch,
|
|
@@ -412,7 +422,7 @@ const createBlockCommit = (
|
|
|
412
422
|
message: block.error ? 'Tool error: ' + block.error : 'Tool call succeeded',
|
|
413
423
|
} satisfies Commit;
|
|
414
424
|
|
|
415
|
-
case '
|
|
425
|
+
case 'stats':
|
|
416
426
|
return {
|
|
417
427
|
id: getGenericBlockId(message.id, idx),
|
|
418
428
|
branch,
|
|
@@ -420,7 +430,7 @@ const createBlockCommit = (
|
|
|
420
430
|
timestamp,
|
|
421
431
|
icon: IconType.ROCKET,
|
|
422
432
|
level: LogLevel.INFO,
|
|
423
|
-
message: ContentBlock.
|
|
433
|
+
message: ContentBlock.createStatsMessage(block),
|
|
424
434
|
} satisfies Commit;
|
|
425
435
|
|
|
426
436
|
case 'status':
|
|
@@ -467,11 +477,11 @@ const getToolCallBranchFromCommitId = (toolCallCommitId: string, toolCallId: str
|
|
|
467
477
|
return `${messageId}_${toolCallId}`;
|
|
468
478
|
};
|
|
469
479
|
|
|
470
|
-
const getToolCallId = (messageId:
|
|
471
|
-
const getToolResultId = (messageId:
|
|
472
|
-
const getGenericBlockId = (messageId:
|
|
480
|
+
const getToolCallId = (messageId: EntityId, toolCallId: string) => `${messageId}_toolCall_${toolCallId}`;
|
|
481
|
+
const getToolResultId = (messageId: EntityId, toolCallId: string) => `${messageId}_toolResult_${toolCallId}`;
|
|
482
|
+
const getGenericBlockId = (messageId: EntityId, idx: number) => `${messageId}_block_${idx}`;
|
|
473
483
|
|
|
474
|
-
const getBranchName = (options: { parentMessage?:
|
|
484
|
+
const getBranchName = (options: { parentMessage?: EntityId; toolCallId?: string }) => {
|
|
475
485
|
if (options.toolCallId) {
|
|
476
486
|
return options.toolCallId;
|
|
477
487
|
} else if (options.parentMessage) {
|
|
@@ -496,14 +506,15 @@ const getParentId = (message: Message.Message) => {
|
|
|
496
506
|
}
|
|
497
507
|
};
|
|
498
508
|
|
|
499
|
-
const stringifyRef = (ref: Ref.
|
|
509
|
+
const stringifyRef = (ref: Ref.Unknown) => {
|
|
500
510
|
if (ref.target) {
|
|
501
511
|
return stringifyObject(ref.target);
|
|
502
512
|
}
|
|
503
513
|
|
|
504
|
-
|
|
514
|
+
const echoUri = EID.tryParse(ref.uri);
|
|
515
|
+
return (echoUri ? EID.getEntityId(echoUri) : undefined) ?? '';
|
|
505
516
|
};
|
|
506
517
|
|
|
507
|
-
const stringifyObject = (obj: Obj.
|
|
518
|
+
const stringifyObject = (obj: Obj.Unknown) => {
|
|
508
519
|
return Obj.getLabel(obj) ?? Obj.getTypename(obj) ?? obj.id;
|
|
509
520
|
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Schema from 'effect/Schema';
|
|
6
|
+
|
|
7
|
+
import { Trace } from '@dxos/compute';
|
|
8
|
+
import { Obj } from '@dxos/echo';
|
|
9
|
+
import { ContentBlock, Actor } from '@dxos/types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Partial content block emitted.
|
|
13
|
+
*/
|
|
14
|
+
export const PartialBlock = Trace.EventType('assistant.partialBlock', {
|
|
15
|
+
schema: Schema.Struct({
|
|
16
|
+
messageId: Obj.ID,
|
|
17
|
+
role: Actor.Role,
|
|
18
|
+
block: ContentBlock.Any,
|
|
19
|
+
}),
|
|
20
|
+
isEphemeral: true,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Complete content block emitted.
|
|
25
|
+
*/
|
|
26
|
+
export const CompleteBlock = Trace.EventType('assistant.completeBlock', {
|
|
27
|
+
schema: Schema.Struct({
|
|
28
|
+
messageId: Obj.ID,
|
|
29
|
+
role: Actor.Role,
|
|
30
|
+
block: ContentBlock.Any,
|
|
31
|
+
}),
|
|
32
|
+
isEphemeral: false,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const AgentRequestBegin = Trace.EventType('assistant.agentRequestBegin', {
|
|
36
|
+
schema: Schema.Struct({}),
|
|
37
|
+
isEphemeral: false,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const AgentRequestEnd = Trace.EventType('assistant.agentRequestEnd', {
|
|
41
|
+
schema: Schema.Struct({
|
|
42
|
+
status: Schema.Literal('success', 'error', 'interrupted'),
|
|
43
|
+
error: Schema.optional(Schema.String),
|
|
44
|
+
}),
|
|
45
|
+
isEphemeral: false,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Emitted when an MCP server connection fails for a request turn.
|
|
50
|
+
* Ephemeral so that misconfigured/unreachable servers don't pollute the durable feed,
|
|
51
|
+
* but can still be surfaced to the user via the live ephemeral event stream.
|
|
52
|
+
*/
|
|
53
|
+
export const McpServerError = Trace.EventType('assistant.mcpServerError', {
|
|
54
|
+
schema: Schema.Struct({
|
|
55
|
+
url: Schema.String,
|
|
56
|
+
protocol: Schema.Literal('sse', 'http'),
|
|
57
|
+
message: Schema.String,
|
|
58
|
+
}),
|
|
59
|
+
isEphemeral: true,
|
|
60
|
+
});
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/extraction/extraction.ts", "../../../../src/extraction/extraction-llm-function/extraction-llm-function.ts", "../../../../src/extraction/extraction-ner-function/extraction-ner-function.ts", "../../../../src/extraction/extraction-ner-function/named-entity-recognition.ts", "../../../../src/extraction/quotes.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { asyncTimeout } from '@dxos/async';\nimport { Expando } from '@dxos/echo/internal';\nimport { type FunctionDefinition } from '@dxos/functions';\nimport { type FunctionExecutor } from '@dxos/functions-runtime';\nimport { log } from '@dxos/log';\nimport { Message } from '@dxos/types';\n\nexport const ExtractionInput = Schema.Struct({\n message: Message.Message,\n objects: Schema.optional(Schema.Array(Expando)),\n options: Schema.optional(\n Schema.Struct({\n timeout: Schema.optional(Schema.Number),\n fallbackToRaw: Schema.optional(Schema.Boolean),\n }),\n ),\n});\nexport interface ExtractionInput extends Schema.Schema.Type<typeof ExtractionInput> {}\n\nexport const ExtractionOutput = Schema.Struct({\n message: Message.Message,\n timeElapsed: Schema.Number,\n});\nexport interface ExtractionOutput extends Schema.Schema.Type<typeof ExtractionOutput> {}\n\nexport type ProcessTranscriptMessageParams = {\n input: ExtractionInput;\n function: FunctionDefinition<ExtractionInput, ExtractionOutput>;\n executor: FunctionExecutor;\n\n options?: {\n /**\n * Timeout for the entity extraction.\n */\n timeout?: number;\n\n /**\n * Fallback to raw text if the entity extraction fails.\n * Otherwise the function will throw an error.\n * @default false\n */\n fallbackToRaw?: boolean;\n };\n};\n\nexport type ExtractionFunction = FunctionDefinition<ExtractionInput, ExtractionOutput>;\n\n/**\n * Extract entities from the transcript message and add them to the message.\n */\n// TODO(dmaretskyi): Move context to a vector search index.\nexport const processTranscriptMessage = async (params: ProcessTranscriptMessageParams): Promise<ExtractionOutput> => {\n try {\n if (params.options?.timeout && params.options.timeout > 0) {\n return await asyncTimeout(params.executor.invoke(params.function, params.input), params.options.timeout);\n } else {\n return await params.executor.invoke(params.function, params.input);\n }\n } catch (error) {\n if (params.options?.fallbackToRaw) {\n log.warn('failed to process message, falling back to raw text', { error });\n return {\n message: params.input.message,\n timeElapsed: 0,\n };\n } else {\n throw error;\n }\n }\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type FunctionDefinition, defineFunction } from '@dxos/functions';\n\nimport { ExtractionInput, ExtractionOutput } from '../extraction';\n\nexport const extractionAnthropicFunction: FunctionDefinition<ExtractionInput, ExtractionOutput> = defineFunction({\n key: 'dxos.org/function/extraction/extract-entities',\n name: 'Extract Entities',\n description: 'Extract entities from the transcript message and add them to the message.',\n inputSchema: ExtractionInput,\n outputSchema: ExtractionOutput,\n handler: async ({ data: { message, objects }, context }) => {\n throw new Error('not implemented');\n // const startTime = performance.now();\n // const ai = context.getService(AiService.AiService);\n // const session = new AiSession({ operationModel: 'configured' });\n // const result = await session.runStructured(ReferencedQuotes, {\n // generationOptions: {\n // model: '@anthropic/claude-3-5-haiku-20241022',\n // },\n // client: ai.client,\n // systemPrompt: PROMPT,\n // history: [\n // Obj.make(DataType.Message.Message, {\n // created: new Date().toISOString(),\n // sender: { role: 'user' },\n // blocks: [\n // {\n // _tag: 'text',\n // text: `<context>${JSON.stringify(objects)}</context>`,\n // } satisfies DataType.ContentBlock.Text,\n // {\n // _tag: 'text',\n // text: `<transcript>${JSON.stringify(message.blocks)}</transcript>`,\n // } satisfies DataType.ContentBlock.Text,\n // ],\n // }),\n // ],\n // artifacts: [],\n // prompt: '',\n // tools: [],\n // } as any); // TODO(burdon): Rewrite test.\n\n // return {\n // timeElapsed: performance.now() - startTime,\n // message: create(DataType.Message.Message, {\n // ...message,\n // blocks: message.blocks.map((block) =>\n // block._tag !== 'transcript'\n // ? block\n // : {\n // ...block,\n // text: insertReferences(block.text, result),\n // },\n // ),\n // }),\n // };\n },\n});\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { defineFunction } from '@dxos/functions';\n\nimport { ExtractionInput, ExtractionOutput } from '../extraction';\n\n/**\n * Named Entity Recognition model\n */\n// TODO(mykola): Make it use vector index to query objects and not pass objects as input.\nexport const extractionNerFunction = defineFunction({\n key: 'dxos.org/function/extraction/extract-entities',\n name: 'Extract Entities',\n description: 'Extracts named entities from a text',\n inputSchema: ExtractionInput,\n outputSchema: ExtractionOutput,\n handler: async ({ data: { message, options }, context }) => {\n throw new Error('not implemented');\n // log.info('input', { message, options });\n // const startTime = performance.now();\n // const { db } = context.getService(DatabaseService);\n // const { extractFullEntities } = await import('./named-entity-recognition');\n\n // const entitiesPromise = Promise.all(\n // message.blocks.map(async (block) => {\n // invariant(block._tag === 'transcript' || block._tag === 'text');\n // return extractFullEntities(block.text);\n // }),\n // ).then((entities) => entities.flat());\n // const entities = options?.timeout ? await asyncTimeout(entitiesPromise, options.timeout) : await entitiesPromise;\n\n // log.info('entities', { entities });\n // const quoteReferences = await findQuotes(\n // entities.map((entity) => entity.word),\n // db,\n // );\n\n // const blocksWithReferences = message.blocks.map((block) => {\n // invariant(block._tag === 'transcript' || block._tag === 'text');\n // return { ...block, text: insertReferences(block._tag, quoteReferences) };\n // });\n\n // const messageWithReferences = create(Message.Message, {\n // ...message,\n // blocks: blocksWithReferences,\n // });\n\n // log.info('output', { messageWithReferences });\n // return {\n // message: messageWithReferences,\n // timeElapsed: performance.now() - startTime,\n // };\n },\n});\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport {\n type TokenClassificationOutput,\n type TokenClassificationPipelineType,\n type TokenClassificationSingle,\n pipeline,\n} from '@xenova/transformers';\n\nimport { log } from '@dxos/log';\n\nlet _ner: Promise<TokenClassificationPipelineType>;\n\n/**\n * Named Entity Recognition pipeline.\n * Initializes the pipeline on first call.\n * @returns The singleton promise that resolves to a token classification pipeline.\n */\nexport const getNer = () => {\n if (!_ner) {\n _ner = pipeline('ner', 'Xenova/bert-base-NER').then((ner) => {\n log.info('NER model is ready');\n return ner;\n });\n }\n\n return _ner;\n};\n\n/**\n * Extracts entities from text using the named entity recognition pipeline and does simple grouping of tokens.\n */\nexport const extractFullEntities = async (text: string): Promise<TokenClassificationSingle[]> => {\n const ner = await getNer();\n const entities = (await ner(text)) as TokenClassificationOutput;\n const tokenGroups = createTokenGroups(entities);\n const combinedEntities = tokenGroups.map(combineNerTokens);\n return combinedEntities;\n};\n\nexport const createTokenGroups = (tokens: TokenClassificationSingle[]): TokenClassificationSingle[][] => {\n const tokenGroups: TokenClassificationSingle[][] = [];\n\n const canBeCombined = (prevToken: TokenClassificationSingle, currentToken: TokenClassificationSingle) => {\n const [currentState, currentEntity] = currentToken.entity.split('-'); // B, I, O\n const [prevState, prevEntity] = prevToken.entity.split('-'); // B, I, O\n if (prevEntity !== currentEntity) {\n return false;\n }\n if (prevState === 'O') {\n return false;\n }\n if (currentState === 'I') {\n return true;\n }\n if ((prevState === 'B' || prevState === 'I') && currentState === 'B') {\n return currentToken.word.startsWith('#');\n }\n return false;\n };\n\n for (const token of tokens) {\n if (tokenGroups.length === 0) {\n tokenGroups.push([token]);\n continue;\n }\n const lastTokenGroup = tokenGroups.at(-1)!;\n if (canBeCombined(lastTokenGroup.at(-1)!, token)) {\n lastTokenGroup.push(token);\n continue;\n }\n tokenGroups.push([token]);\n }\n\n return tokenGroups;\n};\n\nexport const combineNerTokens = (group: TokenClassificationSingle[]): TokenClassificationSingle => {\n const combinedToken: TokenClassificationSingle = {\n entity: group.at(0)!.entity.split('-')[1],\n score: group.reduce((acc, token) => acc + token.score, 0) / group.length,\n index: group.at(0)!.index,\n word: group.at(0)!.word,\n start: group.at(0)!.start,\n end: group.at(-1)!.end,\n };\n\n for (const token of group.slice(1)) {\n if (token.word.startsWith('#')) {\n combinedToken.word += token.word.replace(/^#+/, '');\n } else {\n combinedToken.word += ' ' + token.word;\n }\n }\n\n return combinedToken;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { Filter, Query } from '@dxos/echo';\nimport { ObjectId } from '@dxos/echo/internal';\nimport { type EchoDatabase } from '@dxos/echo-db';\nimport { DXN } from '@dxos/keys';\nimport { log } from '@dxos/log';\n\nexport const ReferencedQuotes = Schema.Struct({\n references: Schema.Array(\n Schema.Struct({\n id: Schema.String,\n quote: Schema.String, // TODO(burdon): Quote?\n }),\n )\n .pipe(Schema.mutable)\n .annotations({\n // TODO(burdon): Does this description make sense?\n description: `\n The references to the context objects that are mentioned in the transcript. \n Quote should match the original transcript text exactly, while id is the id of the context object.\n `,\n }),\n});\nexport type ReferencedQuotes = Schema.Schema.Type<typeof ReferencedQuotes>;\n\nexport const findQuotes = async (quotes: string[], db: EchoDatabase): Promise<ReferencedQuotes> => {\n const references = await Promise.all(\n quotes.map(async (quote) => {\n const { objects } = await db.query(Query.select(Filter.text(quote, { type: 'vector' }))).run();\n log.info('found quotes in vector index', { objects, quote });\n return objects.length > 0 ? [{ id: objects[0].id.toString(), quote }] : [];\n }),\n );\n return { references: references.flat() };\n};\n\n/**\n * Finds and replaces all quotes with DXNs references.\n */\n// TODO(dmaretskyi): Lookup and verifiy ids from provided context.\nexport const insertReferences = (text: string, quotes: ReferencedQuotes) => {\n for (const quote of quotes.references) {\n if (!ObjectId.isValid(quote.id)) {\n continue;\n }\n\n // Use a case-insensitive regular expression to replace the quote.\n const regex = new RegExp(quote.quote.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n text = text.replace(regex, `[${quote.quote}](${DXN.fromLocalObjectId(quote.id).toString()})`);\n }\n\n return text;\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["Schema", "asyncTimeout", "Expando", "log", "Message", "ExtractionInput", "Struct", "message", "objects", "optional", "Array", "options", "timeout", "Number", "fallbackToRaw", "Boolean", "ExtractionOutput", "timeElapsed", "processTranscriptMessage", "params", "executor", "invoke", "function", "input", "error", "warn", "defineFunction", "extractionAnthropicFunction", "defineFunction", "key", "name", "description", "inputSchema", "ExtractionInput", "outputSchema", "ExtractionOutput", "handler", "data", "message", "objects", "context", "Error", "defineFunction", "extractionNerFunction", "defineFunction", "key", "name", "description", "inputSchema", "ExtractionInput", "outputSchema", "ExtractionOutput", "handler", "data", "message", "options", "context", "Error", "pipeline", "log", "_ner", "getNer", "then", "ner", "info", "extractFullEntities", "text", "entities", "tokenGroups", "createTokenGroups", "combinedEntities", "map", "combineNerTokens", "tokens", "canBeCombined", "prevToken", "currentToken", "currentState", "currentEntity", "entity", "split", "prevState", "prevEntity", "word", "startsWith", "token", "length", "push", "lastTokenGroup", "at", "group", "combinedToken", "score", "reduce", "acc", "index", "start", "end", "slice", "replace", "Schema", "Filter", "Query", "ObjectId", "DXN", "log", "ReferencedQuotes", "Struct", "references", "Array", "id", "String", "quote", "pipe", "mutable", "annotations", "description", "findQuotes", "quotes", "db", "Promise", "all", "map", "objects", "query", "select", "text", "type", "run", "info", "length", "toString", "flat", "insertReferences", "isValid", "regex", "RegExp", "replace", "fromLocalObjectId"]
|
|
7
|
-
}
|