@dxos/assistant 0.9.0 → 0.9.1-staging.ee54ba693a
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/neutral/extraction/index.mjs +108 -119
- package/dist/lib/neutral/extraction/index.mjs.map +4 -4
- package/dist/lib/neutral/index.mjs +395 -234
- package/dist/lib/neutral/index.mjs.map +4 -4
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/types/src/extraction/extraction-llm-function/index.d.ts +2 -0
- package/dist/types/src/extraction/extraction-llm-function/index.d.ts.map +1 -0
- package/dist/types/src/extraction/extraction-llm-function/proper-noun-extraction.d.ts +26 -0
- package/dist/types/src/extraction/extraction-llm-function/proper-noun-extraction.d.ts.map +1 -0
- package/dist/types/src/extraction/index.d.ts +1 -1
- package/dist/types/src/extraction/index.d.ts.map +1 -1
- package/dist/types/src/extraction/quotes.d.ts +8 -1
- package/dist/types/src/extraction/quotes.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/request/AiRequest.d.ts +19 -208
- package/dist/types/src/request/AiRequest.d.ts.map +1 -1
- package/dist/types/src/request/format.d.ts +1 -1
- package/dist/types/src/request/format.d.ts.map +1 -1
- package/dist/types/src/session/AiContext.d.ts +27 -105
- package/dist/types/src/session/AiContext.d.ts.map +1 -1
- package/dist/types/src/session/AiSession.d.ts +11 -29
- package/dist/types/src/session/AiSession.d.ts.map +1 -1
- package/dist/types/src/session/Harness.d.ts +122 -0
- package/dist/types/src/session/Harness.d.ts.map +1 -0
- package/dist/types/src/session/SessionLink.d.ts +8 -11
- package/dist/types/src/session/SessionLink.d.ts.map +1 -1
- package/dist/types/src/session/SessionLoader.d.ts +2 -2
- package/dist/types/src/session/SessionLoader.d.ts.map +1 -1
- package/dist/types/src/session/SkillHooks.d.ts +28 -0
- package/dist/types/src/session/SkillHooks.d.ts.map +1 -0
- package/dist/types/src/session/harness-control.d.ts +177 -0
- package/dist/types/src/session/harness-control.d.ts.map +1 -0
- package/dist/types/src/session/index.d.ts +3 -0
- package/dist/types/src/session/index.d.ts.map +1 -1
- package/dist/types/src/session/toolkit.d.ts +4 -4
- package/dist/types/src/session/toolkit.d.ts.map +1 -1
- package/dist/types/src/templates/system.d.ts +4 -6
- package/dist/types/src/templates/system.d.ts.map +1 -1
- package/dist/types/src/tool-runtime/index.d.ts.map +1 -0
- package/dist/types/src/tool-runtime/services.d.ts.map +1 -0
- package/dist/types/src/util/artifact.d.ts.map +1 -1
- package/dist/types/src/util/diff.d.ts +9 -3
- package/dist/types/src/util/diff.d.ts.map +1 -1
- package/dist/types/src/util/tracing.d.ts +40 -0
- package/dist/types/src/util/tracing.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +28 -25
- package/src/extraction/extraction-llm-function/index.ts +5 -0
- package/src/extraction/extraction-llm-function/proper-noun-extraction.ts +78 -0
- package/src/extraction/index.ts +1 -1
- package/src/extraction/quotes.test.ts +67 -2
- package/src/extraction/quotes.ts +47 -13
- package/src/index.ts +1 -1
- package/src/request/AiRequest.ts +45 -14
- package/src/request/format.ts +9 -11
- package/src/session/AiContext.test.ts +52 -32
- package/src/session/AiContext.ts +73 -95
- package/src/session/AiSession.test.ts +4 -4
- package/src/session/AiSession.ts +51 -83
- package/src/session/Harness.ts +241 -0
- package/src/session/SessionLink.ts +8 -8
- package/src/session/SessionLoader.ts +4 -4
- package/src/session/SkillHooks.ts +71 -0
- package/src/session/harness-control.ts +30 -0
- package/src/session/index.ts +3 -0
- package/src/session/toolkit.ts +8 -8
- package/src/templates/instructions/format.tpl +3 -3
- package/src/templates/instructions/system.tpl +10 -12
- package/src/templates/system.ts +6 -2
- package/src/util/artifact.ts +9 -2
- package/src/util/diff.test.ts +4 -4
- package/src/util/diff.ts +15 -8
- package/src/util/tracing.ts +1 -1
- package/dist/types/src/extraction/extraction.d.ts +0 -1677
- package/dist/types/src/extraction/extraction.d.ts.map +0 -1
- package/dist/types/src/functions/index.d.ts.map +0 -1
- package/dist/types/src/functions/services.d.ts.map +0 -1
- package/src/extraction/extraction-llm-function/transcription-instructions.tpl +0 -28
- package/src/extraction/extraction.ts +0 -105
- /package/dist/types/src/{functions → tool-runtime}/index.d.ts +0 -0
- /package/dist/types/src/{functions → tool-runtime}/services.d.ts +0 -0
- /package/src/{functions → tool-runtime}/index.ts +0 -0
- /package/src/{functions → tool-runtime}/services.ts +0 -0
|
@@ -1,78 +1,120 @@
|
|
|
1
1
|
import "../chunk-J5LGTIGS.mjs";
|
|
2
2
|
|
|
3
|
-
// src/extraction/extraction.ts
|
|
4
|
-
import * as
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
3
|
+
// src/extraction/extraction-llm-function/proper-noun-extraction.ts
|
|
4
|
+
import * as LanguageModel from "@effect/ai/LanguageModel";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as Schema2 from "effect/Schema";
|
|
7
|
+
import { AiService } from "@dxos/ai";
|
|
8
|
+
import { Obj } from "@dxos/echo";
|
|
9
9
|
import { Message } from "@dxos/types";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
name: "Entity Extraction (Anthropic)",
|
|
27
|
-
description: "Extract entities from transcript using Anthropic LLM.",
|
|
28
|
-
icon: "ph--text-t--regular"
|
|
29
|
-
},
|
|
30
|
-
input: ExtractionInput,
|
|
31
|
-
output: ExtractionOutput
|
|
32
|
-
});
|
|
33
|
-
var extractionNerFunction = Operation.make({
|
|
34
|
-
meta: {
|
|
35
|
-
key: DXN.make("org.dxos.function.extraction.ner"),
|
|
36
|
-
name: "Entity Extraction (NER)",
|
|
37
|
-
description: "Extract entities from transcript using Named Entity Recognition.",
|
|
38
|
-
icon: "ph--text-t--regular"
|
|
39
|
-
},
|
|
40
|
-
input: ExtractionInput,
|
|
41
|
-
output: ExtractionOutput
|
|
10
|
+
|
|
11
|
+
// src/extraction/quotes.ts
|
|
12
|
+
import * as Schema from "effect/Schema";
|
|
13
|
+
import { Filter, Query } from "@dxos/echo";
|
|
14
|
+
import { EID, EntityId } from "@dxos/keys";
|
|
15
|
+
var ReferencedQuotes = Schema.Struct({
|
|
16
|
+
references: Schema.Array(Schema.Struct({
|
|
17
|
+
id: Schema.String,
|
|
18
|
+
quote: Schema.String
|
|
19
|
+
})).pipe(Schema.mutable).annotations({
|
|
20
|
+
// TODO(burdon): Does this description make sense?
|
|
21
|
+
description: `
|
|
22
|
+
The references to the context objects that are mentioned in the transcript.
|
|
23
|
+
Quote should match the original transcript text exactly, while id is the id of the context object.
|
|
24
|
+
`
|
|
25
|
+
})
|
|
42
26
|
});
|
|
43
|
-
var
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
};
|
|
57
|
-
} else {
|
|
58
|
-
throw error;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
27
|
+
var findReferences = async (nouns, db, { searchKind = "full-text" } = {}) => {
|
|
28
|
+
const normalizedNouns = Array.from(new Set(nouns.map((noun) => noun.trim()).filter((noun) => noun.length > 0))).sort((leftNoun, rightNoun) => rightNoun.length - leftNoun.length);
|
|
29
|
+
const references = await Promise.all(normalizedNouns.map(async (noun) => {
|
|
30
|
+
const objects = await db.query(Query.select(Filter.text(noun, {
|
|
31
|
+
type: searchKind
|
|
32
|
+
}))).run();
|
|
33
|
+
return objects.length > 0 ? [
|
|
34
|
+
{
|
|
35
|
+
id: objects[0].id.toString(),
|
|
36
|
+
quote: noun
|
|
37
|
+
}
|
|
38
|
+
] : [];
|
|
39
|
+
}));
|
|
61
40
|
return {
|
|
62
|
-
|
|
63
|
-
timeElapsed: 0
|
|
41
|
+
references: references.flat()
|
|
64
42
|
};
|
|
65
43
|
};
|
|
44
|
+
var insertReferences = (text, quotes) => {
|
|
45
|
+
const references = quotes.references.filter((quote) => EntityId.isValid(quote.id)).sort((left, right) => right.quote.length - left.quote.length);
|
|
46
|
+
for (const quote of references) {
|
|
47
|
+
const regex = new RegExp(quote.quote.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
|
|
48
|
+
text = replaceOutsideLinks(text, regex, `[${quote.quote}](${EID.make({
|
|
49
|
+
entityId: quote.id
|
|
50
|
+
})})`);
|
|
51
|
+
}
|
|
52
|
+
return text;
|
|
53
|
+
};
|
|
54
|
+
var MARKDOWN_LINK = /\[[^\]]*\]\([^)]*\)/g;
|
|
55
|
+
var replaceOutsideLinks = (text, regex, replacement) => {
|
|
56
|
+
let result = "";
|
|
57
|
+
let plainStart = 0;
|
|
58
|
+
for (const link of text.matchAll(MARKDOWN_LINK)) {
|
|
59
|
+
const index = link.index ?? 0;
|
|
60
|
+
result += text.slice(plainStart, index).replace(regex, replacement) + link[0];
|
|
61
|
+
plainStart = index + link[0].length;
|
|
62
|
+
}
|
|
63
|
+
return result + text.slice(plainStart).replace(regex, replacement);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// src/extraction/extraction-llm-function/proper-noun-extraction.ts
|
|
67
|
+
var EXTRACTION_MODEL = "com.anthropic.model.claude-haiku-4-5.default";
|
|
68
|
+
var ProperNouns = Schema2.Struct({
|
|
69
|
+
properNouns: Schema2.Array(Schema2.String).annotations({
|
|
70
|
+
description: "Proper nouns (names of people, organizations, places, products) mentioned in the text."
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
var extractProperNouns = (text) => Effect.gen(function* () {
|
|
74
|
+
const { value } = yield* Effect.scoped(LanguageModel.generateObject({
|
|
75
|
+
schema: ProperNouns,
|
|
76
|
+
prompt: [
|
|
77
|
+
"Extract every proper noun (people, organizations, places, products) mentioned in the transcript text below.",
|
|
78
|
+
"Return only the surface strings exactly as they appear. Exclude common nouns and pronouns.",
|
|
79
|
+
"",
|
|
80
|
+
"Transcript:",
|
|
81
|
+
text
|
|
82
|
+
].join("\n")
|
|
83
|
+
}));
|
|
84
|
+
return value.properNouns.map((noun) => noun.trim()).filter((noun) => noun.length >= 3);
|
|
85
|
+
}).pipe(Effect.provide(AiService.model(EXTRACTION_MODEL)));
|
|
86
|
+
var enrichTranscriptMessage = (message, { db }) => Effect.gen(function* () {
|
|
87
|
+
const blocks = yield* Effect.forEach(message.blocks, (block) => Effect.gen(function* () {
|
|
88
|
+
if (block._tag !== "transcript") {
|
|
89
|
+
return block;
|
|
90
|
+
}
|
|
91
|
+
const nouns = yield* extractProperNouns(block.text);
|
|
92
|
+
const references = yield* Effect.promise(() => findReferences([
|
|
93
|
+
...nouns
|
|
94
|
+
], db));
|
|
95
|
+
return {
|
|
96
|
+
...block,
|
|
97
|
+
text: insertReferences(block.text, references)
|
|
98
|
+
};
|
|
99
|
+
}));
|
|
100
|
+
return Obj.make(Message.Message, {
|
|
101
|
+
id: message.id,
|
|
102
|
+
sender: message.sender,
|
|
103
|
+
created: message.created,
|
|
104
|
+
properties: message.properties,
|
|
105
|
+
blocks
|
|
106
|
+
});
|
|
107
|
+
});
|
|
66
108
|
|
|
67
109
|
// src/extraction/extraction-ner-function/named-entity-recognition.ts
|
|
68
110
|
import { pipeline } from "@xenova/transformers";
|
|
69
|
-
import { log
|
|
70
|
-
var
|
|
111
|
+
import { log } from "@dxos/log";
|
|
112
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/core/compute/assistant/src/extraction/extraction-ner-function/named-entity-recognition.ts";
|
|
71
113
|
var _ner;
|
|
72
114
|
var getNer = () => {
|
|
73
115
|
if (!_ner) {
|
|
74
116
|
_ner = pipeline("ner", "Xenova/bert-base-NER").then((ner) => {
|
|
75
|
-
|
|
117
|
+
log.info("NER model is ready", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 14, S: void 0 });
|
|
76
118
|
return ner;
|
|
77
119
|
});
|
|
78
120
|
}
|
|
@@ -140,69 +182,16 @@ var combineNerTokens = (group) => {
|
|
|
140
182
|
}
|
|
141
183
|
return combinedToken;
|
|
142
184
|
};
|
|
143
|
-
|
|
144
|
-
// src/extraction/quotes.ts
|
|
145
|
-
import * as Schema2 from "effect/Schema";
|
|
146
|
-
import { Filter, Query } from "@dxos/echo";
|
|
147
|
-
import { EID, EntityId } from "@dxos/keys";
|
|
148
|
-
import { log as log3 } from "@dxos/log";
|
|
149
|
-
var __dxlog_file3 = "/__w/dxos/dxos/packages/core/compute/assistant/src/extraction/quotes.ts";
|
|
150
|
-
var ReferencedQuotes = Schema2.Struct({
|
|
151
|
-
references: Schema2.Array(Schema2.Struct({
|
|
152
|
-
id: Schema2.String,
|
|
153
|
-
quote: Schema2.String
|
|
154
|
-
})).pipe(Schema2.mutable).annotations({
|
|
155
|
-
// TODO(burdon): Does this description make sense?
|
|
156
|
-
description: `
|
|
157
|
-
The references to the context objects that are mentioned in the transcript.
|
|
158
|
-
Quote should match the original transcript text exactly, while id is the id of the context object.
|
|
159
|
-
`
|
|
160
|
-
})
|
|
161
|
-
});
|
|
162
|
-
var findQuotes = async (quotes, db) => {
|
|
163
|
-
const references = await Promise.all(quotes.map(async (quote) => {
|
|
164
|
-
const objects = await db.query(Query.select(Filter.text(quote, {
|
|
165
|
-
type: "vector"
|
|
166
|
-
}))).run();
|
|
167
|
-
log3.info("found quotes in vector index", {
|
|
168
|
-
objects,
|
|
169
|
-
quote
|
|
170
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 25, S: void 0 });
|
|
171
|
-
return objects.length > 0 ? [
|
|
172
|
-
{
|
|
173
|
-
id: objects[0].id.toString(),
|
|
174
|
-
quote
|
|
175
|
-
}
|
|
176
|
-
] : [];
|
|
177
|
-
}));
|
|
178
|
-
return {
|
|
179
|
-
references: references.flat()
|
|
180
|
-
};
|
|
181
|
-
};
|
|
182
|
-
var insertReferences = (text, quotes) => {
|
|
183
|
-
for (const quote of quotes.references) {
|
|
184
|
-
if (!EntityId.isValid(quote.id)) {
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
const regex = new RegExp(quote.quote.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
|
|
188
|
-
text = text.replace(regex, `[${quote.quote}](${EID.make({
|
|
189
|
-
entityId: quote.id
|
|
190
|
-
})})`);
|
|
191
|
-
}
|
|
192
|
-
return text;
|
|
193
|
-
};
|
|
194
185
|
export {
|
|
195
|
-
|
|
196
|
-
ExtractionOutput,
|
|
186
|
+
ProperNouns,
|
|
197
187
|
ReferencedQuotes,
|
|
198
188
|
combineNerTokens,
|
|
199
189
|
createTokenGroups,
|
|
190
|
+
enrichTranscriptMessage,
|
|
200
191
|
extractFullEntities,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
findQuotes,
|
|
192
|
+
extractProperNouns,
|
|
193
|
+
findReferences,
|
|
204
194
|
getNer,
|
|
205
|
-
insertReferences
|
|
206
|
-
processTranscriptMessage
|
|
195
|
+
insertReferences
|
|
207
196
|
};
|
|
208
197
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/extraction/extraction.ts", "../../../../src/extraction/extraction-ner-function/named-entity-recognition.ts"
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport {
|
|
5
|
-
"mappings": ";;;AAIA,YAAYA,YAAY;AAExB,SAASC,iBAAiB;AAC1B,SAASC,
|
|
6
|
-
"names": ["Schema", "
|
|
3
|
+
"sources": ["../../../../src/extraction/extraction-llm-function/proper-noun-extraction.ts", "../../../../src/extraction/quotes.ts", "../../../../src/extraction/extraction-ner-function/named-entity-recognition.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as LanguageModel from '@effect/ai/LanguageModel';\nimport * as Effect from 'effect/Effect';\nimport * as Schema from 'effect/Schema';\n\nimport { AiService } from '@dxos/ai';\nimport { type Database, Obj } from '@dxos/echo';\nimport { Message } from '@dxos/types';\n\nimport { findReferences, insertReferences } from '../quotes';\n\nconst EXTRACTION_MODEL = 'com.anthropic.model.claude-haiku-4-5.default';\n\n/**\n * Proper nouns extracted from transcript text.\n */\nexport const ProperNouns = Schema.Struct({\n properNouns: Schema.Array(Schema.String).annotations({\n description: 'Proper nouns (names of people, organizations, places, products) mentioned in the text.',\n }),\n});\nexport type ProperNouns = Schema.Schema.Type<typeof ProperNouns>;\n\n/**\n * Extracts proper nouns from transcript text using a small LLM (Haiku). Provides the LanguageModel\n * internally so the residual requirement is just {@link AiService.AiService}.\n */\nexport const extractProperNouns = (text: string) =>\n Effect.gen(function* () {\n const { value } = yield* Effect.scoped(\n LanguageModel.generateObject({\n schema: ProperNouns,\n prompt: [\n 'Extract every proper noun (people, organizations, places, products) mentioned in the transcript text below.',\n 'Return only the surface strings exactly as they appear. Exclude common nouns and pronouns.',\n '',\n 'Transcript:',\n text,\n ].join('\\n'),\n }),\n );\n\n // Drop short tokens (e.g. \"IT\"): insertReferences replaces case-insensitive substrings, so a\n // short noun would match inside unrelated words (\"secur[IT]y\") and corrupt neighbouring links.\n return value.properNouns.map((noun) => noun.trim()).filter((noun) => noun.length >= 3);\n }).pipe(Effect.provide(AiService.model(EXTRACTION_MODEL)));\n\n/**\n * Enriches a transcript message: for each transcript block, extracts proper nouns, links them to\n * objects in the space via full-text search, and rewrites the text with `[noun](dxn)` references.\n * Requires {@link AiService.AiService}; takes the space database handle.\n */\nexport const enrichTranscriptMessage = (message: Message.Message, { db }: { db: Database.Database }) =>\n Effect.gen(function* () {\n const blocks = yield* Effect.forEach(message.blocks, (block) =>\n Effect.gen(function* () {\n if (block._tag !== 'transcript') {\n return block;\n }\n\n const nouns = yield* extractProperNouns(block.text);\n const references = yield* Effect.promise(() => findReferences([...nouns], db));\n return { ...block, text: insertReferences(block.text, references) };\n }),\n );\n\n // Preserve the message identity and metadata; enrichment only rewrites transcript block text.\n return Obj.make(Message.Message, {\n id: message.id,\n sender: message.sender,\n created: message.created,\n properties: message.properties,\n blocks,\n });\n });\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { type Database, Filter, Query } from '@dxos/echo';\nimport { EID, EntityId } from '@dxos/keys';\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 type FindReferencesOptions = {\n /** Search backend. Full-text matches proper nouns precisely; vector matches semantically. */\n searchKind?: 'full-text' | 'vector';\n};\n\n/**\n * Finds the best-matching context object for each noun and returns it as a reference.\n */\nexport const findReferences = async (\n nouns: string[],\n db: Database.Database,\n { searchKind = 'full-text' }: FindReferencesOptions = {},\n): Promise<ReferencedQuotes> => {\n // Deduplicate and process longer nouns first: `insertReferences` rewrites case-insensitive\n // substrings, so a repeated or shorter overlapping noun would re-replace already-linked text and\n // produce nested/broken markdown links.\n const normalizedNouns = Array.from(new Set(nouns.map((noun) => noun.trim()).filter((noun) => noun.length > 0))).sort(\n (leftNoun, rightNoun) => rightNoun.length - leftNoun.length,\n );\n\n const references = await Promise.all(\n normalizedNouns.map(async (noun) => {\n const objects = await db.query(Query.select(Filter.text(noun, { type: searchKind }))).run();\n return objects.length > 0 ? [{ id: objects[0].id.toString(), quote: noun }] : [];\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): string => {\n // Process longer quotes first so e.g. \"Sarah Johnson\" is linked before \"Sarah\". Combined with the\n // link-aware replacement below this stops a shorter or overlapping quote from rewriting text that\n // is already part of an inserted link (which would produce nested `[[..](..)](..)` markdown).\n const references = quotes.references\n .filter((quote) => EntityId.isValid(quote.id))\n .sort((left, right) => right.quote.length - left.quote.length);\n\n for (const quote of references) {\n // Case-insensitive match of the (regex-escaped) quote.\n const regex = new RegExp(quote.quote.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n text = replaceOutsideLinks(text, regex, `[${quote.quote}](${EID.make({ entityId: quote.id })})`);\n }\n\n return text;\n};\n\nconst MARKDOWN_LINK = /\\[[^\\]]*\\]\\([^)]*\\)/g;\n\n/** Applies a replacement to every span of `text` that is not already inside a `[label](url)` link. */\nconst replaceOutsideLinks = (text: string, regex: RegExp, replacement: string): string => {\n let result = '';\n let plainStart = 0;\n for (const link of text.matchAll(MARKDOWN_LINK)) {\n const index = link.index ?? 0;\n result += text.slice(plainStart, index).replace(regex, replacement) + link[0];\n plainStart = index + link[0].length;\n }\n return result + text.slice(plainStart).replace(regex, replacement);\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"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["LanguageModel", "Effect", "Schema", "AiService", "Obj", "Message", "Schema", "Filter", "Query", "EID", "EntityId", "ReferencedQuotes", "Struct", "references", "Array", "id", "String", "quote", "pipe", "mutable", "annotations", "description", "findReferences", "nouns", "db", "searchKind", "normalizedNouns", "from", "Set", "map", "noun", "trim", "filter", "length", "sort", "leftNoun", "rightNoun", "Promise", "all", "objects", "query", "select", "text", "type", "run", "toString", "flat", "insertReferences", "quotes", "isValid", "left", "right", "regex", "RegExp", "replace", "replaceOutsideLinks", "make", "entityId", "MARKDOWN_LINK", "replacement", "result", "plainStart", "link", "matchAll", "index", "slice", "EXTRACTION_MODEL", "ProperNouns", "Struct", "properNouns", "Array", "String", "annotations", "description", "extractProperNouns", "text", "gen", "value", "scoped", "generateObject", "schema", "prompt", "join", "map", "noun", "trim", "filter", "length", "pipe", "provide", "AiService", "model", "enrichTranscriptMessage", "message", "db", "blocks", "forEach", "block", "_tag", "nouns", "references", "promise", "findReferences", "insertReferences", "Obj", "make", "Message", "id", "sender", "created", "properties", "pipeline", "log", "_ner", "ner", "entities", "text", "tokenGroups", "createTokenGroups", "combinedEntities", "canBeCombined", "prevToken", "currentToken", "currentState", "prevEntity", "entity", "currentEntity", "prevState", "token", "push", "lastTokenGroup", "score", "reduce", "index", "group", "at", "word", "start", "end", "combinedToken"]
|
|
7
7
|
}
|