@redaksjon/protokoll-engine 0.1.1-dev.0
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 +47 -0
- package/dist/agentic/executor.d.ts +21 -0
- package/dist/agentic/executor.d.ts.map +1 -0
- package/dist/agentic/index.d.ts +27 -0
- package/dist/agentic/index.d.ts.map +1 -0
- package/dist/agentic/registry.d.ts +11 -0
- package/dist/agentic/registry.d.ts.map +1 -0
- package/dist/agentic/tools/lookup-person.d.ts +3 -0
- package/dist/agentic/tools/lookup-person.d.ts.map +1 -0
- package/dist/agentic/tools/lookup-project.d.ts +3 -0
- package/dist/agentic/tools/lookup-project.d.ts.map +1 -0
- package/dist/agentic/tools/route-note.d.ts +3 -0
- package/dist/agentic/tools/route-note.d.ts.map +1 -0
- package/dist/agentic/tools/store-context.d.ts +3 -0
- package/dist/agentic/tools/store-context.d.ts.map +1 -0
- package/dist/agentic/tools/verify-spelling.d.ts +3 -0
- package/dist/agentic/tools/verify-spelling.d.ts.map +1 -0
- package/dist/agentic/types.d.ts +110 -0
- package/dist/agentic/types.d.ts.map +1 -0
- package/dist/constants.d.ts +98 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/feedback/analyzer.d.ts +13 -0
- package/dist/feedback/analyzer.d.ts.map +1 -0
- package/dist/feedback/decision-tracker.d.ts +14 -0
- package/dist/feedback/decision-tracker.d.ts.map +1 -0
- package/dist/feedback/handler.d.ts +14 -0
- package/dist/feedback/handler.d.ts.map +1 -0
- package/dist/feedback/index.d.ts +12 -0
- package/dist/feedback/index.d.ts.map +1 -0
- package/dist/feedback/types.d.ts +72 -0
- package/dist/feedback/types.d.ts.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/index10.js +4 -0
- package/dist/index10.js.map +1 -0
- package/dist/index11.js +22 -0
- package/dist/index11.js.map +1 -0
- package/dist/index12.js +125 -0
- package/dist/index12.js.map +1 -0
- package/dist/index13.js +124 -0
- package/dist/index13.js.map +1 -0
- package/dist/index14.js +296 -0
- package/dist/index14.js.map +1 -0
- package/dist/index15.js +100 -0
- package/dist/index15.js.map +1 -0
- package/dist/index16.js +107 -0
- package/dist/index16.js.map +1 -0
- package/dist/index17.js +185 -0
- package/dist/index17.js.map +1 -0
- package/dist/index18.js +53 -0
- package/dist/index18.js.map +1 -0
- package/dist/index19.js +19 -0
- package/dist/index19.js.map +1 -0
- package/dist/index2.js +33 -0
- package/dist/index2.js.map +1 -0
- package/dist/index20.js +105 -0
- package/dist/index20.js.map +1 -0
- package/dist/index21.js +26 -0
- package/dist/index21.js.map +1 -0
- package/dist/index22.js +49 -0
- package/dist/index22.js.map +1 -0
- package/dist/index23.js +119 -0
- package/dist/index23.js.map +1 -0
- package/dist/index24.js +330 -0
- package/dist/index24.js.map +1 -0
- package/dist/index25.js +57 -0
- package/dist/index25.js.map +1 -0
- package/dist/index26.js +38 -0
- package/dist/index26.js.map +1 -0
- package/dist/index27.js +127 -0
- package/dist/index27.js.map +1 -0
- package/dist/index28.js +157 -0
- package/dist/index28.js.map +1 -0
- package/dist/index29.js +163 -0
- package/dist/index29.js.map +1 -0
- package/dist/index3.js +36 -0
- package/dist/index3.js.map +1 -0
- package/dist/index30.js +173 -0
- package/dist/index30.js.map +1 -0
- package/dist/index31.js +423 -0
- package/dist/index31.js.map +1 -0
- package/dist/index32.js +161 -0
- package/dist/index32.js.map +1 -0
- package/dist/index33.js +152 -0
- package/dist/index33.js.map +1 -0
- package/dist/index34.js +56 -0
- package/dist/index34.js.map +1 -0
- package/dist/index35.js +103 -0
- package/dist/index35.js.map +1 -0
- package/dist/index36.js +451 -0
- package/dist/index36.js.map +1 -0
- package/dist/index37.js +431 -0
- package/dist/index37.js.map +1 -0
- package/dist/index38.js +87 -0
- package/dist/index38.js.map +1 -0
- package/dist/index39.js +122 -0
- package/dist/index39.js.map +1 -0
- package/dist/index4.js +3 -0
- package/dist/index4.js.map +1 -0
- package/dist/index40.js +299 -0
- package/dist/index40.js.map +1 -0
- package/dist/index41.js +49 -0
- package/dist/index41.js.map +1 -0
- package/dist/index42.js +151 -0
- package/dist/index42.js.map +1 -0
- package/dist/index43.js +226 -0
- package/dist/index43.js.map +1 -0
- package/dist/index44.js +49 -0
- package/dist/index44.js.map +1 -0
- package/dist/index45.js +45 -0
- package/dist/index45.js.map +1 -0
- package/dist/index46.js +37 -0
- package/dist/index46.js.map +1 -0
- package/dist/index47.js +51 -0
- package/dist/index47.js.map +1 -0
- package/dist/index48.js +39 -0
- package/dist/index48.js.map +1 -0
- package/dist/index49.js +239 -0
- package/dist/index49.js.map +1 -0
- package/dist/index5.js +17 -0
- package/dist/index5.js.map +1 -0
- package/dist/index50.js +163 -0
- package/dist/index50.js.map +1 -0
- package/dist/index51.js +81 -0
- package/dist/index51.js.map +1 -0
- package/dist/index52.js +78 -0
- package/dist/index52.js.map +1 -0
- package/dist/index53.js +22 -0
- package/dist/index53.js.map +1 -0
- package/dist/index54.js +8 -0
- package/dist/index54.js.map +1 -0
- package/dist/index55.js +8 -0
- package/dist/index55.js.map +1 -0
- package/dist/index56.js +17 -0
- package/dist/index56.js.map +1 -0
- package/dist/index57.js +4 -0
- package/dist/index57.js.map +1 -0
- package/dist/index58.js +17 -0
- package/dist/index58.js.map +1 -0
- package/dist/index59.js +4 -0
- package/dist/index59.js.map +1 -0
- package/dist/index6.js +22 -0
- package/dist/index6.js.map +1 -0
- package/dist/index60.js +6 -0
- package/dist/index60.js.map +1 -0
- package/dist/index7.js +27 -0
- package/dist/index7.js.map +1 -0
- package/dist/index8.js +22 -0
- package/dist/index8.js.map +1 -0
- package/dist/index9.js +5 -0
- package/dist/index9.js.map +1 -0
- package/dist/logging.d.ts +7 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/output/index.d.ts +15 -0
- package/dist/output/index.d.ts.map +1 -0
- package/dist/phases/complete.d.ts +17 -0
- package/dist/phases/complete.d.ts.map +1 -0
- package/dist/phases/index.d.ts +5 -0
- package/dist/phases/index.d.ts.map +1 -0
- package/dist/phases/locate.d.ts +15 -0
- package/dist/phases/locate.d.ts.map +1 -0
- package/dist/phases/simple-replace.d.ts +72 -0
- package/dist/phases/simple-replace.d.ts.map +1 -0
- package/dist/phases/transcribe.d.ts +19 -0
- package/dist/phases/transcribe.d.ts.map +1 -0
- package/dist/pipeline/index.d.ts +10 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/orchestrator.d.ts +13 -0
- package/dist/pipeline/orchestrator.d.ts.map +1 -0
- package/dist/pipeline/types.d.ts +58 -0
- package/dist/pipeline/types.d.ts.map +1 -0
- package/dist/prompt/index.d.ts +3 -0
- package/dist/prompt/index.d.ts.map +1 -0
- package/dist/prompt/templates.d.ts +40 -0
- package/dist/prompt/templates.d.ts.map +1 -0
- package/dist/prompt/transcribe.d.ts +42 -0
- package/dist/prompt/transcribe.d.ts.map +1 -0
- package/dist/reasoning/client.d.ts +42 -0
- package/dist/reasoning/client.d.ts.map +1 -0
- package/dist/reasoning/index.d.ts +17 -0
- package/dist/reasoning/index.d.ts.map +1 -0
- package/dist/reasoning/strategy.d.ts +12 -0
- package/dist/reasoning/strategy.d.ts.map +1 -0
- package/dist/reasoning/types.d.ts +58 -0
- package/dist/reasoning/types.d.ts.map +1 -0
- package/dist/reflection/collector.d.ts +18 -0
- package/dist/reflection/collector.d.ts.map +1 -0
- package/dist/reflection/index.d.ts +13 -0
- package/dist/reflection/index.d.ts.map +1 -0
- package/dist/reflection/reporter.d.ts +10 -0
- package/dist/reflection/reporter.d.ts.map +1 -0
- package/dist/reflection/types.d.ts +99 -0
- package/dist/reflection/types.d.ts.map +1 -0
- package/dist/routing/classifier.d.ts +8 -0
- package/dist/routing/classifier.d.ts.map +1 -0
- package/dist/routing/index.d.ts +12 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/router.d.ts +8 -0
- package/dist/routing/router.d.ts.map +1 -0
- package/dist/routing/types.d.ts +68 -0
- package/dist/routing/types.d.ts.map +1 -0
- package/dist/transcript/feedback.d.ts +70 -0
- package/dist/transcript/feedback.d.ts.map +1 -0
- package/dist/transcript/index.d.ts +10 -0
- package/dist/transcript/index.d.ts.map +1 -0
- package/dist/transcript/operations.d.ts +152 -0
- package/dist/transcript/operations.d.ts.map +1 -0
- package/dist/transcript/pkl-utils.d.ts +66 -0
- package/dist/transcript/pkl-utils.d.ts.map +1 -0
- package/dist/transcription/index.d.ts +17 -0
- package/dist/transcription/index.d.ts.map +1 -0
- package/dist/transcription/service.d.ts +10 -0
- package/dist/transcription/service.d.ts.map +1 -0
- package/dist/transcription/types.d.ts +41 -0
- package/dist/transcription/types.d.ts.map +1 -0
- package/dist/types.d.ts +28 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/util/collision-detector.d.ts +77 -0
- package/dist/util/collision-detector.d.ts.map +1 -0
- package/dist/util/dates.d.ts +57 -0
- package/dist/util/dates.d.ts.map +1 -0
- package/dist/util/general.d.ts +3 -0
- package/dist/util/general.d.ts.map +1 -0
- package/dist/util/media.d.ts +9 -0
- package/dist/util/media.d.ts.map +1 -0
- package/dist/util/metadata.d.ts +138 -0
- package/dist/util/metadata.d.ts.map +1 -0
- package/dist/util/openai.d.ts +22 -0
- package/dist/util/openai.d.ts.map +1 -0
- package/dist/util/sounds-like-database.d.ts +98 -0
- package/dist/util/sounds-like-database.d.ts.map +1 -0
- package/dist/util/storage.d.ts +35 -0
- package/dist/util/storage.d.ts.map +1 -0
- package/dist/util/text-replacer.d.ts +56 -0
- package/dist/util/text-replacer.d.ts.map +1 -0
- package/dist/utils/entityFinder.d.ts +29 -0
- package/dist/utils/entityFinder.d.ts.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index47.js","sources":["../src/util/openai.ts"],"sourcesContent":["import { OpenAI } from 'openai';\nimport { ChatCompletionCreateParamsNonStreaming, ChatCompletionMessageParam } from 'openai/resources/chat/completions';\nimport * as Storage from '@/util/storage';\nimport { getLogger } from '@/logging';\nimport { DEFAULT_MODEL, DEFAULT_TRANSCRIPTION_MODEL } from '@/constants';\n\nexport interface Transcription {\n text: string;\n}\n\nexport class OpenAIError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'OpenAIError';\n }\n}\n\n\nexport async function createCompletion(messages: ChatCompletionMessageParam[], options: { responseFormat?: any, model?: string, reasoningLevel?: 'none' | 'low' | 'medium' | 'high', maxTokens?: number, debug?: boolean, debugFile?: string, reason?: string } = {}): Promise<string | any> {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n try {\n const apiKey = process.env.OPENAI_API_KEY;\n if (!apiKey) {\n throw new OpenAIError('OPENAI_API_KEY environment variable is not set');\n }\n\n const openai = new OpenAI({\n apiKey: apiKey,\n });\n\n const model = options.model || DEFAULT_MODEL;\n \n // Check if model supports reasoning_effort\n const supportsReasoning = model.includes('gpt-5') || \n model.includes('o1') || model.includes('o3');\n const isReasoningCall = supportsReasoning && options.reasoningLevel && options.reasoningLevel !== 'none';\n \n logger.debug('Sending prompt to OpenAI: %j', messages);\n\n const startTime = Date.now();\n \n const requestParams: Record<string, unknown> = {\n model,\n messages,\n max_completion_tokens: options.maxTokens || 10000,\n response_format: options.responseFormat,\n };\n \n if (isReasoningCall) {\n requestParams.reasoning_effort = options.reasoningLevel;\n logger.debug('Using reasoning_effort: %s', options.reasoningLevel);\n }\n \n const completion = await openai.chat.completions.create(\n requestParams as unknown as ChatCompletionCreateParamsNonStreaming\n );\n const duration = ((Date.now() - startTime) / 1000).toFixed(1);\n\n // Log token usage with reason if provided\n const usage = completion.usage;\n const reasonSuffix = options.reason ? ` - ${options.reason}` : '';\n if (usage) {\n logger.info('%s (%ss, %d→%d tokens)%s', \n model, duration, usage.prompt_tokens, usage.completion_tokens, reasonSuffix);\n } else {\n logger.info('%s (%ss)%s', model, duration, reasonSuffix);\n }\n\n if (options.debug && options.debugFile) {\n await storage.writeFile(options.debugFile, JSON.stringify(completion, null, 2), 'utf8');\n logger.debug('Wrote debug file to %s', options.debugFile);\n }\n\n const response = completion.choices[0]?.message?.content?.trim();\n if (!response) {\n // Log the full completion object to help debug\n logger.error('Empty response from OpenAI. Full completion object: %j', completion);\n throw new OpenAIError('No response received from OpenAI');\n }\n\n logger.debug('Received response from OpenAI: %s', response);\n if (options.responseFormat) {\n return JSON.parse(response);\n } else {\n return response;\n }\n\n } catch (error: any) {\n logger.error('Error calling OpenAI API: %s %s', error.message, error.stack);\n throw new OpenAIError(`Failed to create completion: ${error.message}`);\n }\n}\n\nexport async function transcribeAudio(filePath: string, options: { model?: string, debug?: boolean, debugFile?: string } = {}): Promise<Transcription> {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n try {\n const apiKey = process.env.OPENAI_API_KEY;\n if (!apiKey) {\n throw new OpenAIError('OPENAI_API_KEY environment variable is not set');\n }\n\n const openai = new OpenAI({\n apiKey: apiKey,\n });\n\n const model = options.model || DEFAULT_TRANSCRIPTION_MODEL;\n const fileName = filePath.split('/').pop() || filePath;\n logger.debug('Transcribing: %s (full path: %s)', fileName, filePath);\n\n const startTime = Date.now();\n const audioStream = await storage.readStream(filePath);\n const transcription = await openai.audio.transcriptions.create({\n model,\n file: audioStream,\n response_format: \"json\",\n });\n \n if (!transcription) {\n throw new OpenAIError('No transcription received from OpenAI');\n }\n \n const duration = ((Date.now() - startTime) / 1000).toFixed(1);\n logger.info('%s (%ss, %d chars)', model, duration, transcription.text?.length || 0);\n\n if (options.debug && options.debugFile) {\n await storage.writeFile(options.debugFile, JSON.stringify(transcription, null, 2), 'utf8');\n logger.debug('Wrote debug file to %s', options.debugFile);\n }\n\n logger.debug('Received transcription from OpenAI: %s', transcription);\n return transcription;\n\n } catch (error: any) {\n logger.error('Error transcribing audio file: %s %s', error.message, error.stack);\n throw new OpenAIError(`Failed to transcribe audio: ${error.message}`);\n }\n}\n"],"names":["storage","Storage.create"],"mappings":";;;;;AAUO,MAAM,oBAAoB,KAAA,CAAM;AAAA,EACnC,YAAY,OAAA,EAAiB;AACzB,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AAAA,EAChB;AACJ;AA+EA,eAAsB,eAAA,CAAgB,QAAA,EAAkB,OAAA,GAAmE,EAAC,EAA2B;AACnJ,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,MAAMA,YAAUC,MAAQ,CAAO,EAAE,GAAA,EAAK,MAAA,CAAO,OAAO,CAAA;AACpD,EAAA,IAAI;AACA,IAAA,MAAM,MAAA,GAAS,QAAQ,GAAA,CAAI,cAAA;AAC3B,IAAA,IAAI,CAAC,MAAA,EAAQ;AACT,MAAA,MAAM,IAAI,YAAY,gDAAgD,CAAA;AAAA,IAC1E;AAEA,IAAA,MAAM,MAAA,GAAS,IAAI,MAAA,CAAO;AAAA,MACtB;AAAA,KACH,CAAA;AAED,IAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,2BAAA;AAC/B,IAAA,MAAM,WAAW,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,CAAE,KAAI,IAAK,QAAA;AAC9C,IAAA,MAAA,CAAO,KAAA,CAAM,kCAAA,EAAoC,QAAA,EAAU,QAAQ,CAAA;AAEnE,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,IAAA,MAAM,WAAA,GAAc,MAAMD,SAAA,CAAQ,UAAA,CAAW,QAAQ,CAAA;AACrD,IAAA,MAAM,aAAA,GAAgB,MAAM,MAAA,CAAO,KAAA,CAAM,eAAe,MAAA,CAAO;AAAA,MAC3D,KAAA;AAAA,MACA,IAAA,EAAM,WAAA;AAAA,MACN,eAAA,EAAiB;AAAA,KACpB,CAAA;AAED,IAAA,IAAI,CAAC,aAAA,EAAe;AAChB,MAAA,MAAM,IAAI,YAAY,uCAAuC,CAAA;AAAA,IACjE;AAEA,IAAA,MAAM,aAAa,IAAA,CAAK,GAAA,KAAQ,SAAA,IAAa,GAAA,EAAM,QAAQ,CAAC,CAAA;AAC5D,IAAA,MAAA,CAAO,KAAK,oBAAA,EAAsB,KAAA,EAAO,UAAU,aAAA,CAAc,IAAA,EAAM,UAAU,CAAC,CAAA;AAElF,IAAA,IAAI,OAAA,CAAQ,KAAA,IAAS,OAAA,CAAQ,SAAA,EAAW;AACpC,MAAA,MAAMA,SAAA,CAAQ,SAAA,CAAU,OAAA,CAAQ,SAAA,EAAW,IAAA,CAAK,UAAU,aAAA,EAAe,IAAA,EAAM,CAAC,CAAA,EAAG,MAAM,CAAA;AACzF,MAAA,MAAA,CAAO,KAAA,CAAM,wBAAA,EAA0B,OAAA,CAAQ,SAAS,CAAA;AAAA,IAC5D;AAEA,IAAA,MAAA,CAAO,KAAA,CAAM,0CAA0C,aAAa,CAAA;AACpE,IAAA,OAAO,aAAA;AAAA,EAEX,SAAS,KAAA,EAAY;AACjB,IAAA,MAAA,CAAO,KAAA,CAAM,sCAAA,EAAwC,KAAA,CAAM,OAAA,EAAS,MAAM,KAAK,CAAA;AAC/E,IAAA,MAAM,IAAI,WAAA,CAAY,CAAA,4BAAA,EAA+B,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA,EACxE;AACJ;;;;"}
|
package/dist/index48.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const stringifyJSON = function(obj) {
|
|
2
|
+
const arrOfKeyVals = [];
|
|
3
|
+
const arrVals = [];
|
|
4
|
+
let objKeys = [];
|
|
5
|
+
if (typeof obj === "number" || typeof obj === "boolean" || obj === null)
|
|
6
|
+
return "" + obj;
|
|
7
|
+
else if (typeof obj === "string")
|
|
8
|
+
return '"' + obj + '"';
|
|
9
|
+
else if (Array.isArray(obj)) {
|
|
10
|
+
if (obj[0] === void 0)
|
|
11
|
+
return "[]";
|
|
12
|
+
else {
|
|
13
|
+
obj.forEach(function(el) {
|
|
14
|
+
arrVals.push(stringifyJSON(el));
|
|
15
|
+
});
|
|
16
|
+
return "[" + arrVals + "]";
|
|
17
|
+
}
|
|
18
|
+
} else if (obj instanceof Object) {
|
|
19
|
+
objKeys = Object.keys(obj);
|
|
20
|
+
objKeys.forEach(function(key) {
|
|
21
|
+
const keyOut = '"' + key + '":';
|
|
22
|
+
const keyValOut = obj[key];
|
|
23
|
+
if (keyValOut instanceof Function || keyValOut === void 0)
|
|
24
|
+
arrOfKeyVals.push("");
|
|
25
|
+
else if (typeof keyValOut === "string")
|
|
26
|
+
arrOfKeyVals.push(keyOut + '"' + keyValOut + '"');
|
|
27
|
+
else if (typeof keyValOut === "boolean" || typeof keyValOut === "number" || keyValOut === null)
|
|
28
|
+
arrOfKeyVals.push(keyOut + keyValOut);
|
|
29
|
+
else if (keyValOut instanceof Object) {
|
|
30
|
+
arrOfKeyVals.push(keyOut + stringifyJSON(keyValOut));
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return "{" + arrOfKeyVals + "}";
|
|
34
|
+
}
|
|
35
|
+
return "";
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export { stringifyJSON };
|
|
39
|
+
//# sourceMappingURL=index48.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index48.js","sources":["../src/util/general.ts"],"sourcesContent":["// Utility function for deep merging two objects.\nexport function deepMerge(target: any, source: any): any {\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n // Block prototype-polluting keys\n if (key === '__proto__' || key === 'constructor') {\n continue;\n }\n if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {\n if (!target[key]) {\n target[key] = {};\n }\n deepMerge(target[key], source[key]);\n } else {\n target[key] = source[key];\n }\n }\n }\n return target;\n}\n\n//Recursive implementation of jSON.stringify;\nexport const stringifyJSON = function (obj: any): string {\n\n const arrOfKeyVals: string[] = [];\n const arrVals: string[] = [];\n let objKeys: string[] = [];\n\n /*********CHECK FOR PRIMITIVE TYPES**********/\n if (typeof obj === 'number' || typeof obj === 'boolean' || obj === null)\n return '' + obj;\n else if (typeof obj === 'string')\n return '\"' + obj + '\"';\n\n /*********CHECK FOR ARRAY**********/\n else if (Array.isArray(obj)) {\n //check for empty array\n if (obj[0] === undefined)\n return '[]';\n else {\n obj.forEach(function (el) {\n arrVals.push(stringifyJSON(el));\n });\n return '[' + arrVals + ']';\n }\n }\n /*********CHECK FOR OBJECT**********/\n else if (obj instanceof Object) {\n //get object keys\n objKeys = Object.keys(obj);\n //set key output;\n objKeys.forEach(function (key) {\n const keyOut = '\"' + key + '\":';\n const keyValOut = obj[key];\n //skip functions and undefined properties\n if (keyValOut instanceof Function || keyValOut === undefined)\n arrOfKeyVals.push('');\n else if (typeof keyValOut === 'string')\n arrOfKeyVals.push(keyOut + '\"' + keyValOut + '\"');\n else if (typeof keyValOut === 'boolean' || typeof keyValOut === 'number' || keyValOut === null)\n arrOfKeyVals.push(keyOut + keyValOut);\n //check for nested objects, call recursively until no more objects\n else if (keyValOut instanceof Object) {\n arrOfKeyVals.push(keyOut + stringifyJSON(keyValOut));\n }\n });\n return '{' + arrOfKeyVals + '}';\n }\n return '';\n};"],"names":[],"mappings":"AAsBO,MAAM,aAAA,GAAgB,SAAU,GAAA,EAAkB;AAErD,EAAA,MAAM,eAAyB,EAAC;AAChC,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,IAAI,UAAoB,EAAC;AAGzB,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,OAAO,GAAA,KAAQ,aAAa,GAAA,KAAQ,IAAA;AAC/D,IAAA,OAAO,EAAA,GAAK,GAAA;AAAA,OAAA,IACP,OAAO,GAAA,KAAQ,QAAA;AACpB,IAAA,OAAO,MAAM,GAAA,GAAM,GAAA;AAAA,OAAA,IAGd,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AAEzB,IAAA,IAAI,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA;AACX,MAAA,OAAO,IAAA;AAAA,SACN;AACD,MAAA,GAAA,CAAI,OAAA,CAAQ,SAAU,EAAA,EAAI;AACtB,QAAA,OAAA,CAAQ,IAAA,CAAK,aAAA,CAAc,EAAE,CAAC,CAAA;AAAA,MAClC,CAAC,CAAA;AACD,MAAA,OAAO,MAAM,OAAA,GAAU,GAAA;AAAA,IAC3B;AAAA,EACJ,CAAA,MAAA,IAES,eAAe,MAAA,EAAQ;AAE5B,IAAA,OAAA,GAAU,MAAA,CAAO,KAAK,GAAG,CAAA;AAEzB,IAAA,OAAA,CAAQ,OAAA,CAAQ,SAAU,GAAA,EAAK;AAC3B,MAAA,MAAM,MAAA,GAAS,MAAM,GAAA,GAAM,IAAA;AAC3B,MAAA,MAAM,SAAA,GAAY,IAAI,GAAG,CAAA;AAEzB,MAAA,IAAI,SAAA,YAAqB,YAAY,SAAA,KAAc,MAAA;AAC/C,QAAA,YAAA,CAAa,KAAK,EAAE,CAAA;AAAA,WAAA,IACf,OAAO,SAAA,KAAc,QAAA;AAC1B,QAAA,YAAA,CAAa,IAAA,CAAK,MAAA,GAAS,GAAA,GAAM,SAAA,GAAY,GAAG,CAAA;AAAA,WAAA,IAC3C,OAAO,SAAA,KAAc,SAAA,IAAa,OAAO,SAAA,KAAc,YAAY,SAAA,KAAc,IAAA;AACtF,QAAA,YAAA,CAAa,IAAA,CAAK,SAAS,SAAS,CAAA;AAAA,WAAA,IAE/B,qBAAqB,MAAA,EAAQ;AAClC,QAAA,YAAA,CAAa,IAAA,CAAK,MAAA,GAAS,aAAA,CAAc,SAAS,CAAC,CAAA;AAAA,MACvD;AAAA,IACJ,CAAC,CAAA;AACD,IAAA,OAAO,MAAM,YAAA,GAAe,GAAA;AAAA,EAChC;AACA,EAAA,OAAO,EAAA;AACX;;;;"}
|
package/dist/index49.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { getLogger } from './index41.js';
|
|
2
|
+
import * as yaml from 'js-yaml';
|
|
3
|
+
import * as fs from 'fs/promises';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import * as os from 'node:os';
|
|
6
|
+
|
|
7
|
+
const create = (config) => {
|
|
8
|
+
const logger = getLogger();
|
|
9
|
+
const database = {
|
|
10
|
+
mappings: [],
|
|
11
|
+
tier1: [],
|
|
12
|
+
tier2: /* @__PURE__ */ new Map(),
|
|
13
|
+
tier3: [],
|
|
14
|
+
collisions: /* @__PURE__ */ new Map(),
|
|
15
|
+
commonTerms: new Set(DEFAULT_COMMON_TERMS),
|
|
16
|
+
genericTerms: new Set(DEFAULT_GENERIC_TERMS)
|
|
17
|
+
};
|
|
18
|
+
const findProtokolDirectories = async () => {
|
|
19
|
+
const homeDir = os.homedir();
|
|
20
|
+
const primaryPath = path.join(homeDir, ".protokoll", "context");
|
|
21
|
+
const dirs = [];
|
|
22
|
+
try {
|
|
23
|
+
await fs.access(primaryPath);
|
|
24
|
+
dirs.push(primaryPath);
|
|
25
|
+
logger.debug(`Found protokoll context at: ${primaryPath}`);
|
|
26
|
+
} catch {
|
|
27
|
+
logger.debug(`No protokoll context found at: ${primaryPath}`);
|
|
28
|
+
}
|
|
29
|
+
return dirs;
|
|
30
|
+
};
|
|
31
|
+
const loadProjectsFromProtokoll = async () => {
|
|
32
|
+
logger.debug("Loading projects from protokoll context");
|
|
33
|
+
const contextDirs = await findProtokolDirectories();
|
|
34
|
+
if (contextDirs.length === 0) {
|
|
35
|
+
logger.warn("No protokoll context directories found");
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
const mappings = [];
|
|
39
|
+
for (const contextDir of contextDirs) {
|
|
40
|
+
const projectsDir = path.join(contextDir, "projects");
|
|
41
|
+
try {
|
|
42
|
+
const files = await fs.readdir(projectsDir);
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
|
|
45
|
+
try {
|
|
46
|
+
const content = await fs.readFile(path.join(projectsDir, file), "utf-8");
|
|
47
|
+
const parsed = yaml.load(content);
|
|
48
|
+
if (!parsed || !parsed.id || !parsed.name) {
|
|
49
|
+
logger.debug(`Skipping invalid project file: ${file}`);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (parsed.active === false) {
|
|
53
|
+
logger.debug(`Skipping inactive project: ${parsed.id}`);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (parsed.sounds_like && parsed.sounds_like.length > 0) {
|
|
57
|
+
for (const soundsLike of parsed.sounds_like) {
|
|
58
|
+
mappings.push({
|
|
59
|
+
soundsLike: soundsLike.toLowerCase(),
|
|
60
|
+
correctText: parsed.name,
|
|
61
|
+
entityType: "project",
|
|
62
|
+
entityId: parsed.id,
|
|
63
|
+
scopedToProjects: null,
|
|
64
|
+
// Will be determined by collision detection
|
|
65
|
+
collisionRisk: "none",
|
|
66
|
+
// Will be determined by collision detection
|
|
67
|
+
tier: 1
|
|
68
|
+
// Will be determined by collision detection
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
logger.debug(`Loaded ${parsed.sounds_like.length} sounds_like entries for project: ${parsed.id}`);
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
logger.warn(`Failed to parse project file ${file}: ${error.message}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
logger.debug(`Could not read projects directory ${projectsDir}: ${error.message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
logger.info(`Loaded ${mappings.length} sounds_like mappings from protokoll projects`);
|
|
82
|
+
return mappings;
|
|
83
|
+
};
|
|
84
|
+
const detectCollisions = (mappings) => {
|
|
85
|
+
const collisionMap = /* @__PURE__ */ new Map();
|
|
86
|
+
for (const mapping of mappings) {
|
|
87
|
+
const key = mapping.soundsLike.toLowerCase();
|
|
88
|
+
if (!collisionMap.has(key)) {
|
|
89
|
+
collisionMap.set(key, []);
|
|
90
|
+
}
|
|
91
|
+
collisionMap.get(key).push(mapping);
|
|
92
|
+
}
|
|
93
|
+
const collisions = /* @__PURE__ */ new Map();
|
|
94
|
+
for (const [soundsLike, conflictMappings] of collisionMap) {
|
|
95
|
+
if (conflictMappings.length > 1) {
|
|
96
|
+
collisions.set(soundsLike, {
|
|
97
|
+
soundsLike,
|
|
98
|
+
mappings: conflictMappings,
|
|
99
|
+
count: conflictMappings.length
|
|
100
|
+
});
|
|
101
|
+
logger.debug(`Collision detected for "${soundsLike}": ${conflictMappings.length} mappings`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
logger.info(`Detected ${collisions.size} collisions in sounds_like mappings`);
|
|
105
|
+
return collisions;
|
|
106
|
+
};
|
|
107
|
+
const classifyTier = (mapping) => {
|
|
108
|
+
if (!mapping.soundsLike) {
|
|
109
|
+
return 3;
|
|
110
|
+
}
|
|
111
|
+
const soundsLikeLower = mapping.soundsLike.toLowerCase();
|
|
112
|
+
if (database.genericTerms.has(soundsLikeLower)) {
|
|
113
|
+
return 3;
|
|
114
|
+
}
|
|
115
|
+
if (database.commonTerms.has(soundsLikeLower)) {
|
|
116
|
+
return 2;
|
|
117
|
+
}
|
|
118
|
+
if (database.collisions.has(soundsLikeLower)) {
|
|
119
|
+
return 2;
|
|
120
|
+
}
|
|
121
|
+
return 1;
|
|
122
|
+
};
|
|
123
|
+
const assignTiersAndCollisions = (mappings) => {
|
|
124
|
+
for (const mapping of mappings) {
|
|
125
|
+
mapping.tier = classifyTier(mapping);
|
|
126
|
+
if (database.collisions.has(mapping.soundsLike.toLowerCase())) {
|
|
127
|
+
mapping.collisionRisk = "high";
|
|
128
|
+
} else if (database.commonTerms.has(mapping.soundsLike.toLowerCase())) {
|
|
129
|
+
mapping.collisionRisk = "medium";
|
|
130
|
+
} else if (mapping.tier === 2) {
|
|
131
|
+
mapping.collisionRisk = "low";
|
|
132
|
+
} else {
|
|
133
|
+
mapping.collisionRisk = "none";
|
|
134
|
+
}
|
|
135
|
+
if (mapping.tier === 2 && mapping.entityType === "project") {
|
|
136
|
+
mapping.scopedToProjects = [mapping.entityId];
|
|
137
|
+
mapping.minConfidence = 0.6;
|
|
138
|
+
}
|
|
139
|
+
logger.debug(
|
|
140
|
+
`Classified "${mapping.soundsLike}" → "${mapping.correctText}" (${mapping.entityType}:${mapping.entityId}) as Tier ${mapping.tier} (risk: ${mapping.collisionRisk})`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
const organizeMappingsByTier = (mappings) => {
|
|
145
|
+
database.tier1 = [];
|
|
146
|
+
database.tier2 = /* @__PURE__ */ new Map();
|
|
147
|
+
database.tier3 = [];
|
|
148
|
+
for (const mapping of mappings) {
|
|
149
|
+
if (mapping.tier === 1) {
|
|
150
|
+
database.tier1.push(mapping);
|
|
151
|
+
} else if (mapping.tier === 2) {
|
|
152
|
+
if (mapping.entityType === "project") {
|
|
153
|
+
if (!database.tier2.has(mapping.entityId)) {
|
|
154
|
+
database.tier2.set(mapping.entityId, []);
|
|
155
|
+
}
|
|
156
|
+
database.tier2.get(mapping.entityId).push(mapping);
|
|
157
|
+
} else {
|
|
158
|
+
if (!database.tier2.has("_generic")) {
|
|
159
|
+
database.tier2.set("_generic", []);
|
|
160
|
+
}
|
|
161
|
+
database.tier2.get("_generic").push(mapping);
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
database.tier3.push(mapping);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
logger.info(
|
|
168
|
+
`Organized mappings: Tier 1=${database.tier1.length}, Tier 2=${Array.from(database.tier2.values()).reduce((sum, arr) => sum + arr.length, 0)}, Tier 3=${database.tier3.length}`
|
|
169
|
+
);
|
|
170
|
+
};
|
|
171
|
+
const load = async () => {
|
|
172
|
+
logger.info("Loading sounds_like database");
|
|
173
|
+
const projectMappings = await loadProjectsFromProtokoll();
|
|
174
|
+
const allMappings = [
|
|
175
|
+
...projectMappings
|
|
176
|
+
// ...peopleMappings,
|
|
177
|
+
// ...termMappings,
|
|
178
|
+
];
|
|
179
|
+
database.mappings = allMappings;
|
|
180
|
+
{
|
|
181
|
+
database.collisions = detectCollisions(allMappings);
|
|
182
|
+
}
|
|
183
|
+
assignTiersAndCollisions(allMappings);
|
|
184
|
+
organizeMappingsByTier(allMappings);
|
|
185
|
+
logger.info(`Sounds_like database loaded: ${allMappings.length} total mappings`);
|
|
186
|
+
return database;
|
|
187
|
+
};
|
|
188
|
+
const getTier1Mappings = () => {
|
|
189
|
+
return database.tier1;
|
|
190
|
+
};
|
|
191
|
+
const getTier2MappingsForProject = (projectId) => {
|
|
192
|
+
const projectMappings = database.tier2.get(projectId) ?? [];
|
|
193
|
+
const genericMappings = database.tier2.get("_generic") ?? [];
|
|
194
|
+
return [...projectMappings, ...genericMappings];
|
|
195
|
+
};
|
|
196
|
+
const hasCollision = (soundsLike) => {
|
|
197
|
+
return database.collisions.has(soundsLike.toLowerCase());
|
|
198
|
+
};
|
|
199
|
+
const getCollision = (soundsLike) => {
|
|
200
|
+
return database.collisions.get(soundsLike.toLowerCase());
|
|
201
|
+
};
|
|
202
|
+
const getAllCollisions = () => {
|
|
203
|
+
return Array.from(database.collisions.values());
|
|
204
|
+
};
|
|
205
|
+
return {
|
|
206
|
+
load,
|
|
207
|
+
getTier1Mappings,
|
|
208
|
+
getTier2MappingsForProject,
|
|
209
|
+
hasCollision,
|
|
210
|
+
getCollision,
|
|
211
|
+
getAllCollisions,
|
|
212
|
+
classifyTier
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
const DEFAULT_COMMON_TERMS = [
|
|
216
|
+
"protocol",
|
|
217
|
+
"observation",
|
|
218
|
+
"composition",
|
|
219
|
+
"gateway",
|
|
220
|
+
"service",
|
|
221
|
+
"system",
|
|
222
|
+
"platform"
|
|
223
|
+
];
|
|
224
|
+
const DEFAULT_GENERIC_TERMS = [
|
|
225
|
+
"meeting",
|
|
226
|
+
"update",
|
|
227
|
+
"work",
|
|
228
|
+
"project",
|
|
229
|
+
"task",
|
|
230
|
+
"issue",
|
|
231
|
+
"discussion",
|
|
232
|
+
"review",
|
|
233
|
+
"the",
|
|
234
|
+
"a",
|
|
235
|
+
"an"
|
|
236
|
+
];
|
|
237
|
+
|
|
238
|
+
export { create };
|
|
239
|
+
//# sourceMappingURL=index49.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index49.js","sources":["../src/util/sounds-like-database.ts"],"sourcesContent":["/**\n * Sounds-Like Database\n *\n * Aggregates sounds_like mappings from multiple sources (projects, people, terms)\n * and provides efficient lookup and collision detection for entity correction.\n *\n * Part of the simple-replace optimization (Phase 1).\n */\n\nimport * as Logging from '@/logging';\nimport * as yaml from 'js-yaml';\nimport * as fs from 'fs/promises';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\n\n/**\n * Represents a single sounds_like mapping entry\n */\nexport interface SoundsLikeMapping {\n /** What Whisper typically hears (e.g., \"protocol\", \"observation\") */\n soundsLike: string;\n\n /** Correct text to replace with (e.g., \"Protokoll\", \"Observasjon\") */\n correctText: string;\n\n /** Type of entity (project, person, or term) */\n entityType: 'project' | 'person' | 'term';\n\n /** Unique identifier for the entity */\n entityId: string;\n\n /** Only apply replacement in these project contexts (null = apply everywhere) */\n scopedToProjects?: string[] | null;\n\n /** Collision risk level: none (Tier 1), low/medium (Tier 2), high (Tier 3) */\n collisionRisk: 'none' | 'low' | 'medium' | 'high';\n\n /** Tier classification (1 = always safe, 2 = project-scoped, 3 = ambiguous) */\n tier: 1 | 2 | 3;\n\n /** Minimum confidence required for Tier 2 replacements */\n minConfidence?: number;\n}\n\n/**\n * Collision information for a sounds_like value\n */\nexport interface Collision {\n /** The sounds_like value that has collisions */\n soundsLike: string;\n\n /** All mappings that share this sounds_like value */\n mappings: SoundsLikeMapping[];\n\n /** Number of conflicting mappings */\n count: number;\n}\n\n/**\n * Database of sounds_like mappings with collision detection\n */\nexport interface SoundsLikeDatabase {\n /** All loaded mappings */\n mappings: SoundsLikeMapping[];\n\n /** Tier 1 mappings (always safe to apply) */\n tier1: SoundsLikeMapping[];\n\n /** Tier 2 mappings (require project-scoping) */\n tier2: Map<string, SoundsLikeMapping[]>; // Keyed by project ID\n\n /** Tier 3 mappings (too ambiguous, skip) */\n tier3: SoundsLikeMapping[];\n\n /** Detected collisions */\n collisions: Map<string, Collision>;\n\n /** Common terms that should not be replaced */\n commonTerms: Set<string>;\n\n /** Generic terms to always skip (Tier 3) */\n genericTerms: Set<string>;\n}\n\n/**\n * Configuration for the sounds-like database\n */\nexport interface DatabaseConfig {\n /** Protokoll context directories to load from */\n protokollContextPaths?: string[];\n\n /** Confidence threshold for Tier 2 replacements */\n tier2Confidence?: number;\n\n /** Enable collision detection */\n detectCollisions?: boolean;\n\n /** Custom common terms list */\n commonTerms?: string[];\n\n /** Custom generic terms list */\n genericTerms?: string[];\n}\n\n/**\n * Instance interface for the sounds-like database\n */\nexport interface Instance {\n /** Load all sounds_like mappings from sources */\n load(): Promise<SoundsLikeDatabase>;\n\n /** Get all Tier 1 (always safe) mappings */\n getTier1Mappings(): SoundsLikeMapping[];\n\n /** Get Tier 2 (project-scoped) mappings for a specific project */\n getTier2MappingsForProject(projectId: string): SoundsLikeMapping[];\n\n /** Check if a sounds_like value has collisions */\n hasCollision(soundsLike: string): boolean;\n\n /** Get collision info for a sounds_like value */\n getCollision(soundsLike: string): Collision | undefined;\n\n /** Get all collisions */\n getAllCollisions(): Collision[];\n\n /** Classify a mapping into a tier based on collision risk */\n classifyTier(mapping: Partial<SoundsLikeMapping>): 1 | 2 | 3;\n}\n\ninterface ProtokolProject {\n id: string;\n name: string;\n type: 'project';\n sounds_like?: string[];\n classification?: {\n context_type?: 'work' | 'personal' | 'mixed';\n };\n active?: boolean;\n}\n\n/**\n * Create a sounds-like database instance\n */\nexport const create = (config?: DatabaseConfig): Instance => {\n const logger = Logging.getLogger();\n\n const database: SoundsLikeDatabase = {\n mappings: [],\n tier1: [],\n tier2: new Map(),\n tier3: [],\n collisions: new Map(),\n commonTerms: new Set(config?.commonTerms ?? DEFAULT_COMMON_TERMS),\n genericTerms: new Set(config?.genericTerms ?? DEFAULT_GENERIC_TERMS),\n };\n\n /**\n * Find protokoll context directories\n */\n const findProtokolDirectories = async (): Promise<string[]> => {\n if (config?.protokollContextPaths) {\n return config.protokollContextPaths;\n }\n\n const homeDir = os.homedir();\n const primaryPath = path.join(homeDir, '.protokoll', 'context');\n\n const dirs: string[] = [];\n\n // Check primary protokoll directory\n try {\n await fs.access(primaryPath);\n dirs.push(primaryPath);\n logger.debug(`Found protokoll context at: ${primaryPath}`);\n } catch {\n logger.debug(`No protokoll context found at: ${primaryPath}`);\n }\n\n return dirs;\n };\n\n /**\n * Load projects from protokoll context\n */\n const loadProjectsFromProtokoll = async (): Promise<SoundsLikeMapping[]> => {\n logger.debug('Loading projects from protokoll context');\n\n const contextDirs = await findProtokolDirectories();\n\n if (contextDirs.length === 0) {\n logger.warn('No protokoll context directories found');\n return [];\n }\n\n const mappings: SoundsLikeMapping[] = [];\n\n for (const contextDir of contextDirs) {\n const projectsDir = path.join(contextDir, 'projects');\n\n try {\n const files = await fs.readdir(projectsDir);\n\n for (const file of files) {\n if (!file.endsWith('.yaml') && !file.endsWith('.yml')) continue;\n\n try {\n const content = await fs.readFile(path.join(projectsDir, file), 'utf-8');\n const parsed = yaml.load(content) as Partial<ProtokolProject>;\n\n if (!parsed || !parsed.id || !parsed.name) {\n logger.debug(`Skipping invalid project file: ${file}`);\n continue;\n }\n\n // Skip inactive projects\n if (parsed.active === false) {\n logger.debug(`Skipping inactive project: ${parsed.id}`);\n continue;\n }\n\n // Process sounds_like entries\n if (parsed.sounds_like && parsed.sounds_like.length > 0) {\n for (const soundsLike of parsed.sounds_like) {\n mappings.push({\n soundsLike: soundsLike.toLowerCase(),\n correctText: parsed.name,\n entityType: 'project',\n entityId: parsed.id,\n scopedToProjects: null, // Will be determined by collision detection\n collisionRisk: 'none', // Will be determined by collision detection\n tier: 1, // Will be determined by collision detection\n });\n }\n logger.debug(`Loaded ${parsed.sounds_like.length} sounds_like entries for project: ${parsed.id}`);\n }\n } catch (error: any) {\n logger.warn(`Failed to parse project file ${file}: ${error.message}`);\n }\n }\n } catch (error: any) {\n logger.debug(`Could not read projects directory ${projectsDir}: ${error.message}`);\n }\n }\n\n logger.info(`Loaded ${mappings.length} sounds_like mappings from protokoll projects`);\n return mappings;\n };\n\n /**\n * Detect collisions in mappings\n */\n const detectCollisions = (mappings: SoundsLikeMapping[]): Map<string, Collision> => {\n const collisionMap = new Map<string, SoundsLikeMapping[]>();\n\n // Group by sounds_like value (case-insensitive)\n for (const mapping of mappings) {\n const key = mapping.soundsLike.toLowerCase();\n if (!collisionMap.has(key)) {\n collisionMap.set(key, []);\n }\n collisionMap.get(key)!.push(mapping);\n }\n\n // Identify actual collisions (multiple mappings for same sounds_like)\n const collisions = new Map<string, Collision>();\n for (const [soundsLike, conflictMappings] of collisionMap) {\n if (conflictMappings.length > 1) {\n collisions.set(soundsLike, {\n soundsLike,\n mappings: conflictMappings,\n count: conflictMappings.length,\n });\n logger.debug(`Collision detected for \"${soundsLike}\": ${conflictMappings.length} mappings`);\n }\n }\n\n logger.info(`Detected ${collisions.size} collisions in sounds_like mappings`);\n return collisions;\n };\n\n /**\n * Classify a mapping into a tier based on collision risk\n */\n const classifyTier = (mapping: Partial<SoundsLikeMapping>): 1 | 2 | 3 => {\n if (!mapping.soundsLike) {\n return 3; // Invalid, treat as ambiguous\n }\n\n const soundsLikeLower = mapping.soundsLike.toLowerCase();\n\n // Tier 3: Generic terms (always skip)\n if (database.genericTerms.has(soundsLikeLower)) {\n return 3;\n }\n\n // Tier 2: Common terms (require project-scoping)\n if (database.commonTerms.has(soundsLikeLower)) {\n return 2;\n }\n\n // Tier 2: Has collision with other mappings\n if (database.collisions.has(soundsLikeLower)) {\n return 2;\n }\n\n // Tier 1: Unique, no collisions, not a common term\n return 1;\n };\n\n /**\n * Assign tiers and collision info to all mappings\n */\n const assignTiersAndCollisions = (mappings: SoundsLikeMapping[]): void => {\n for (const mapping of mappings) {\n // Classify tier\n mapping.tier = classifyTier(mapping);\n\n // Determine collision risk\n if (database.collisions.has(mapping.soundsLike.toLowerCase())) {\n mapping.collisionRisk = 'high';\n } else if (database.commonTerms.has(mapping.soundsLike.toLowerCase())) {\n mapping.collisionRisk = 'medium';\n } else if (mapping.tier === 2) {\n mapping.collisionRisk = 'low';\n } else {\n mapping.collisionRisk = 'none';\n }\n\n // Scope to projects for Tier 2\n if (mapping.tier === 2 && mapping.entityType === 'project') {\n mapping.scopedToProjects = [mapping.entityId];\n mapping.minConfidence = config?.tier2Confidence ?? 0.6;\n }\n\n logger.debug(\n `Classified \"${mapping.soundsLike}\" → \"${mapping.correctText}\" ` +\n `(${mapping.entityType}:${mapping.entityId}) as Tier ${mapping.tier} ` +\n `(risk: ${mapping.collisionRisk})`\n );\n }\n };\n\n /**\n * Organize mappings by tier\n */\n const organizeMappingsByTier = (mappings: SoundsLikeMapping[]): void => {\n database.tier1 = [];\n database.tier2 = new Map();\n database.tier3 = [];\n\n for (const mapping of mappings) {\n if (mapping.tier === 1) {\n database.tier1.push(mapping);\n } else if (mapping.tier === 2) {\n // Organize Tier 2 by project ID for efficient lookup\n if (mapping.entityType === 'project') {\n if (!database.tier2.has(mapping.entityId)) {\n database.tier2.set(mapping.entityId, []);\n }\n database.tier2.get(mapping.entityId)!.push(mapping);\n } else {\n // For non-project entities in Tier 2, add to a generic bucket\n if (!database.tier2.has('_generic')) {\n database.tier2.set('_generic', []);\n }\n database.tier2.get('_generic')!.push(mapping);\n }\n } else {\n database.tier3.push(mapping);\n }\n }\n\n logger.info(\n `Organized mappings: Tier 1=${database.tier1.length}, ` +\n `Tier 2=${Array.from(database.tier2.values()).reduce((sum, arr) => sum + arr.length, 0)}, ` +\n `Tier 3=${database.tier3.length}`\n );\n };\n\n /**\n * Load all sounds_like mappings\n */\n const load = async (): Promise<SoundsLikeDatabase> => {\n logger.info('Loading sounds_like database');\n\n // Load from all sources\n const projectMappings = await loadProjectsFromProtokoll();\n // TODO: Load from people source\n // TODO: Load from terms source\n\n const allMappings = [\n ...projectMappings,\n // ...peopleMappings,\n // ...termMappings,\n ];\n\n database.mappings = allMappings;\n\n // Detect collisions\n if (config?.detectCollisions !== false) {\n database.collisions = detectCollisions(allMappings);\n }\n\n // Assign tiers and collision info\n assignTiersAndCollisions(allMappings);\n\n // Organize by tier for efficient lookup\n organizeMappingsByTier(allMappings);\n\n logger.info(`Sounds_like database loaded: ${allMappings.length} total mappings`);\n\n return database;\n };\n\n /**\n * Get Tier 1 mappings (always safe)\n */\n const getTier1Mappings = (): SoundsLikeMapping[] => {\n return database.tier1;\n };\n\n /**\n * Get Tier 2 mappings for a specific project\n */\n const getTier2MappingsForProject = (projectId: string): SoundsLikeMapping[] => {\n const projectMappings = database.tier2.get(projectId) ?? [];\n const genericMappings = database.tier2.get('_generic') ?? [];\n return [...projectMappings, ...genericMappings];\n };\n\n /**\n * Check if a sounds_like value has collisions\n */\n const hasCollision = (soundsLike: string): boolean => {\n return database.collisions.has(soundsLike.toLowerCase());\n };\n\n /**\n * Get collision info\n */\n const getCollision = (soundsLike: string): Collision | undefined => {\n return database.collisions.get(soundsLike.toLowerCase());\n };\n\n /**\n * Get all collisions\n */\n const getAllCollisions = (): Collision[] => {\n return Array.from(database.collisions.values());\n };\n\n return {\n load,\n getTier1Mappings,\n getTier2MappingsForProject,\n hasCollision,\n getCollision,\n getAllCollisions,\n classifyTier,\n };\n};\n\n/**\n * Default common terms that indicate Tier 2 (project-scoped) replacements\n */\nconst DEFAULT_COMMON_TERMS = [\n 'protocol',\n 'observation',\n 'composition',\n 'gateway',\n 'service',\n 'system',\n 'platform',\n];\n\n/**\n * Default generic terms that should never be replaced (Tier 3)\n */\nconst DEFAULT_GENERIC_TERMS = [\n 'meeting',\n 'update',\n 'work',\n 'project',\n 'task',\n 'issue',\n 'discussion',\n 'review',\n 'the',\n 'a',\n 'an',\n];\n"],"names":["Logging.getLogger"],"mappings":"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"}
|
package/dist/index5.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { create as create$1 } from './index24.js';
|
|
2
|
+
import { create as create$2 } from './index25.js';
|
|
3
|
+
export { CorrectedEntitySchema, ReferencedEntitiesSchema, RoutingDecisionSchema, ToolResultSchema } from './index26.js';
|
|
4
|
+
|
|
5
|
+
const create = (reasoning, toolContext) => {
|
|
6
|
+
const executor = create$1(reasoning, toolContext);
|
|
7
|
+
return {
|
|
8
|
+
process: (transcriptText) => executor.process(transcriptText),
|
|
9
|
+
getAvailableTools: () => {
|
|
10
|
+
const registry = create$2(toolContext);
|
|
11
|
+
return registry.getTools().map((t) => t.name);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export { create };
|
|
17
|
+
//# sourceMappingURL=index5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index5.js","sources":["../src/agentic/index.ts"],"sourcesContent":["/**\n * Agentic Transcription System\n * \n * Main entry point for the agentic transcription system. Provides tool-based\n * enhancement of transcripts using reasoning models.\n * \n * The agentic approach means the model queries context via tools rather than\n * receiving all context upfront in the prompt. This allows for:\n * - Smaller prompt sizes\n * - More targeted context retrieval \n * - Better handling of large context sets\n */\n\nimport { ToolContext, TranscriptionState } from './types';\nimport * as Executor from './executor';\nimport * as Registry from './registry';\nimport * as Reasoning from '../reasoning';\n\nexport interface ContextChangeRecord {\n entityType: 'person' | 'project' | 'company' | 'term' | 'ignored';\n entityId: string;\n entityName: string;\n action: 'created' | 'updated';\n details?: Record<string, unknown>;\n}\n\nexport interface AgenticInstance {\n process(transcriptText: string): Promise<{\n enhancedText: string;\n state: TranscriptionState;\n toolsUsed: string[];\n iterations: number;\n totalTokens?: number;\n contextChanges?: ContextChangeRecord[];\n }>;\n getAvailableTools(): string[];\n}\n\n/**\n * Create an agentic executor from a ToolContext\n * This is the primary factory method - always agentic, no flags needed\n */\nexport const create = (\n reasoning: Reasoning.ReasoningInstance,\n toolContext: ToolContext\n): AgenticInstance => {\n const executor = Executor.create(reasoning, toolContext);\n \n return {\n process: (transcriptText: string) => executor.process(transcriptText),\n \n getAvailableTools: () => {\n const registry = Registry.create(toolContext);\n return registry.getTools().map(t => t.name);\n },\n };\n};\n\n// Re-export types\nexport * from './types';\n\n"],"names":["Executor.create","Registry.create"],"mappings":";;;;AA0CO,MAAM,MAAA,GAAS,CAClB,SAAA,EACA,WAAA,KACkB;AAClB,EAAA,MAAM,QAAA,GAAWA,QAAS,CAAO,SAAA,EAAW,WAAW,CAAA;AAEvD,EAAA,OAAO;AAAA,IACH,OAAA,EAAS,CAAC,cAAA,KAA2B,QAAA,CAAS,QAAQ,cAAc,CAAA;AAAA,IAEpE,mBAAmB,MAAM;AACrB,MAAA,MAAM,QAAA,GAAWC,QAAS,CAAO,WAAW,CAAA;AAC5C,MAAA,OAAO,SAAS,QAAA,EAAS,CAAE,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,IAAI,CAAA;AAAA,IAC9C;AAAA,GACJ;AACJ;;;;"}
|
package/dist/index50.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { getLogger } from './index41.js';
|
|
2
|
+
|
|
3
|
+
const create = (config) => {
|
|
4
|
+
const logger = getLogger();
|
|
5
|
+
const tier2MinConfidence = config?.tier2MinConfidence;
|
|
6
|
+
const useCapitalizationHints = config?.useCapitalizationHints ?? true;
|
|
7
|
+
const shouldApplyTier2 = (mapping, classification) => {
|
|
8
|
+
if (mapping.tier !== 2) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const confidence = classification.confidence ?? 0;
|
|
12
|
+
const minConfidence = mapping.minConfidence ?? tier2MinConfidence;
|
|
13
|
+
if (confidence < minConfidence) {
|
|
14
|
+
logger.debug(
|
|
15
|
+
`Skipping Tier 2 replacement for "${mapping.soundsLike}": confidence ${confidence} < ${minConfidence}`
|
|
16
|
+
);
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
if (mapping.scopedToProjects && mapping.scopedToProjects.length > 0) {
|
|
20
|
+
const classifiedProject = classification.project;
|
|
21
|
+
if (!classifiedProject) {
|
|
22
|
+
logger.debug(
|
|
23
|
+
`Skipping Tier 2 replacement for "${mapping.soundsLike}": no project in classification`
|
|
24
|
+
);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (!mapping.scopedToProjects.includes(classifiedProject)) {
|
|
28
|
+
logger.debug(
|
|
29
|
+
`Skipping Tier 2 replacement for "${mapping.soundsLike}": project "${classifiedProject}" not in scope [${mapping.scopedToProjects.join(", ")}]`
|
|
30
|
+
);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
logger.debug(
|
|
35
|
+
`Applying Tier 2 replacement for "${mapping.soundsLike}" → "${mapping.correctText}" (project: ${classification.project}, confidence: ${confidence})`
|
|
36
|
+
);
|
|
37
|
+
return true;
|
|
38
|
+
};
|
|
39
|
+
const resolveCollision = (collision, classification) => {
|
|
40
|
+
const { soundsLike, mappings } = collision;
|
|
41
|
+
logger.debug(`Resolving collision for "${soundsLike}" (${mappings.length} candidates)`);
|
|
42
|
+
const tier1Mappings = mappings.filter((m) => m.tier === 1);
|
|
43
|
+
const tier2Mappings = mappings.filter((m) => m.tier === 2 && shouldApplyTier2(m, classification));
|
|
44
|
+
if (tier1Mappings.length === 1) {
|
|
45
|
+
logger.debug(`Resolved collision: using Tier 1 mapping "${tier1Mappings[0].correctText}"`);
|
|
46
|
+
return tier1Mappings[0];
|
|
47
|
+
}
|
|
48
|
+
if (tier1Mappings.length > 1) {
|
|
49
|
+
logger.warn(`Multiple Tier 1 mappings for "${soundsLike}", skipping replacement`);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
if (tier2Mappings.length === 1) {
|
|
53
|
+
logger.debug(`Resolved collision: using Tier 2 mapping "${tier2Mappings[0].correctText}"`);
|
|
54
|
+
return tier2Mappings[0];
|
|
55
|
+
}
|
|
56
|
+
if (tier2Mappings.length > 1) {
|
|
57
|
+
logger.debug(`Multiple Tier 2 mappings match for "${soundsLike}", skipping replacement`);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
logger.debug(`No applicable mappings for collision "${soundsLike}"`);
|
|
61
|
+
return null;
|
|
62
|
+
};
|
|
63
|
+
const detectCapitalizationHint = (soundsLike, surroundingText) => {
|
|
64
|
+
if (!useCapitalizationHints || !surroundingText) {
|
|
65
|
+
return "unknown";
|
|
66
|
+
}
|
|
67
|
+
const regex = new RegExp(`\\b${soundsLike}\\b`, "i");
|
|
68
|
+
const match = surroundingText.match(regex);
|
|
69
|
+
if (!match) {
|
|
70
|
+
return "unknown";
|
|
71
|
+
}
|
|
72
|
+
const matchedText = match[0];
|
|
73
|
+
const isCapitalized = matchedText[0] === matchedText[0].toUpperCase();
|
|
74
|
+
if (!isCapitalized) {
|
|
75
|
+
return "common-term";
|
|
76
|
+
}
|
|
77
|
+
const indexInText = surroundingText.indexOf(matchedText);
|
|
78
|
+
const beforeText = surroundingText.substring(0, indexInText).trimEnd();
|
|
79
|
+
const isAtSentenceStart = beforeText.length === 0 || /[.!?]\s*$/.test(beforeText);
|
|
80
|
+
if (isAtSentenceStart) {
|
|
81
|
+
return "unknown";
|
|
82
|
+
}
|
|
83
|
+
return "proper-noun";
|
|
84
|
+
};
|
|
85
|
+
const decideReplacement = (context) => {
|
|
86
|
+
const { classification, soundsLike, availableMappings, surroundingText } = context;
|
|
87
|
+
if (availableMappings.length === 0) {
|
|
88
|
+
return {
|
|
89
|
+
shouldReplace: false,
|
|
90
|
+
reason: "No mappings available",
|
|
91
|
+
confidence: 1
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (availableMappings.length === 1) {
|
|
95
|
+
const mapping = availableMappings[0];
|
|
96
|
+
if (mapping.tier === 1) {
|
|
97
|
+
return {
|
|
98
|
+
shouldReplace: true,
|
|
99
|
+
mapping,
|
|
100
|
+
reason: "Tier 1 mapping (always safe)",
|
|
101
|
+
confidence: 1
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (mapping.tier === 2) {
|
|
105
|
+
if (shouldApplyTier2(mapping, classification)) {
|
|
106
|
+
return {
|
|
107
|
+
shouldReplace: true,
|
|
108
|
+
mapping,
|
|
109
|
+
reason: `Tier 2 mapping (project: ${classification.project}, confidence: ${classification.confidence})`,
|
|
110
|
+
confidence: classification.confidence ?? 0.5
|
|
111
|
+
};
|
|
112
|
+
} else {
|
|
113
|
+
return {
|
|
114
|
+
shouldReplace: false,
|
|
115
|
+
reason: "Tier 2 conditions not met",
|
|
116
|
+
confidence: 0.5
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
shouldReplace: false,
|
|
122
|
+
reason: "Tier 3 mapping (too ambiguous)",
|
|
123
|
+
confidence: 1
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const resolvedMapping = resolveCollision(
|
|
127
|
+
{ soundsLike, mappings: availableMappings, count: availableMappings.length },
|
|
128
|
+
classification
|
|
129
|
+
);
|
|
130
|
+
if (resolvedMapping) {
|
|
131
|
+
return {
|
|
132
|
+
shouldReplace: true,
|
|
133
|
+
mapping: resolvedMapping,
|
|
134
|
+
reason: `Collision resolved (${availableMappings.length} candidates)`,
|
|
135
|
+
confidence: classification.confidence ?? 0.5
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
if (surroundingText && useCapitalizationHints) {
|
|
139
|
+
const hint = detectCapitalizationHint(soundsLike, surroundingText);
|
|
140
|
+
if (hint === "common-term") {
|
|
141
|
+
return {
|
|
142
|
+
shouldReplace: false,
|
|
143
|
+
reason: "Capitalization hint suggests common term",
|
|
144
|
+
confidence: 0.7
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
shouldReplace: false,
|
|
150
|
+
reason: "Collision could not be resolved",
|
|
151
|
+
confidence: 0.5
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
decideReplacement,
|
|
156
|
+
shouldApplyTier2,
|
|
157
|
+
resolveCollision,
|
|
158
|
+
detectCapitalizationHint
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export { create };
|
|
163
|
+
//# sourceMappingURL=index50.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index50.js","sources":["../src/util/collision-detector.ts"],"sourcesContent":["/**\n * Collision Detector\n *\n * Provides utilities for detecting and resolving collisions in sounds_like mappings.\n * Helps determine when it's safe to apply a replacement and when context is needed.\n *\n * Part of the simple-replace optimization (Phase 1).\n */\n\nimport * as Logging from '@/logging';\nimport { SoundsLikeMapping, Collision } from './sounds-like-database';\n\n/**\n * Classification result for an entity\n */\nexport interface Classification {\n /** Identified project ID */\n project?: string;\n\n /** Classification confidence (0-1) */\n confidence?: number;\n\n /** Additional classification metadata */\n [key: string]: any;\n}\n\n/**\n * Replacement decision\n */\nexport interface ReplacementDecision {\n /** Whether to apply the replacement */\n shouldReplace: boolean;\n\n /** The mapping to use (if shouldReplace is true) */\n mapping?: SoundsLikeMapping;\n\n /** Reason for the decision */\n reason: string;\n\n /** Confidence in this decision (0-1) */\n confidence: number;\n}\n\n/**\n * Context for collision resolution\n */\nexport interface CollisionContext {\n /** Classification of the transcription */\n classification: Classification;\n\n /** The sounds_like value being considered */\n soundsLike: string;\n\n /** Available mappings for this sounds_like */\n availableMappings: SoundsLikeMapping[];\n\n /** Surrounding text context (optional) */\n surroundingText?: string;\n}\n\n/**\n * Instance interface for collision detector\n */\nexport interface Instance {\n /**\n * Decide whether to apply a replacement given a collision context\n */\n decideReplacement(context: CollisionContext): ReplacementDecision;\n\n /**\n * Check if a Tier 2 mapping should be applied given classification\n */\n shouldApplyTier2(mapping: SoundsLikeMapping, classification: Classification): boolean;\n\n /**\n * Resolve a collision by selecting the best mapping\n */\n resolveCollision(collision: Collision, classification: Classification): SoundsLikeMapping | null;\n\n /**\n * Detect capitalization hints in context\n */\n detectCapitalizationHint(soundsLike: string, surroundingText: string): 'proper-noun' | 'common-term' | 'unknown';\n}\n\n/**\n * Configuration for collision detector\n */\nexport interface CollisionDetectorConfig {\n /** Minimum confidence for Tier 2 replacements (default: 0.6) */\n tier2MinConfidence?: number;\n\n /** High confidence threshold for aggressive replacement (default: 0.8) */\n tier2HighConfidence?: number;\n\n /** Enable capitalization hints (default: true) */\n useCapitalizationHints?: boolean;\n\n /** Enable surrounding text analysis (default: false, future feature) */\n useSurroundingText?: boolean;\n}\n\n/**\n * Create a collision detector instance\n */\nexport const create = (config?: CollisionDetectorConfig): Instance => {\n const logger = Logging.getLogger();\n\n const tier2MinConfidence = config?.tier2MinConfidence ?? 0.6;\n // const tier2HighConfidence = config?.tier2HighConfidence ?? 0.8; // Reserved for future use\n const useCapitalizationHints = config?.useCapitalizationHints ?? true;\n\n /**\n * Check if a Tier 2 mapping should be applied\n */\n const shouldApplyTier2 = (\n mapping: SoundsLikeMapping,\n classification: Classification\n ): boolean => {\n // Must be Tier 2\n if (mapping.tier !== 2) {\n return false;\n }\n\n // Check confidence threshold\n const confidence = classification.confidence ?? 0;\n const minConfidence = mapping.minConfidence ?? tier2MinConfidence;\n\n if (confidence < minConfidence) {\n logger.debug(\n `Skipping Tier 2 replacement for \"${mapping.soundsLike}\": ` +\n `confidence ${confidence} < ${minConfidence}`\n );\n return false;\n }\n\n // For project-scoped mappings, check if project matches\n if (mapping.scopedToProjects && mapping.scopedToProjects.length > 0) {\n const classifiedProject = classification.project;\n\n if (!classifiedProject) {\n logger.debug(\n `Skipping Tier 2 replacement for \"${mapping.soundsLike}\": ` +\n `no project in classification`\n );\n return false;\n }\n\n if (!mapping.scopedToProjects.includes(classifiedProject)) {\n logger.debug(\n `Skipping Tier 2 replacement for \"${mapping.soundsLike}\": ` +\n `project \"${classifiedProject}\" not in scope [${mapping.scopedToProjects.join(', ')}]`\n );\n return false;\n }\n }\n\n logger.debug(\n `Applying Tier 2 replacement for \"${mapping.soundsLike}\" → \"${mapping.correctText}\" ` +\n `(project: ${classification.project}, confidence: ${confidence})`\n );\n return true;\n };\n\n /**\n * Resolve a collision by selecting the best mapping\n */\n const resolveCollision = (\n collision: Collision,\n classification: Classification\n ): SoundsLikeMapping | null => {\n const { soundsLike, mappings } = collision;\n\n logger.debug(`Resolving collision for \"${soundsLike}\" (${mappings.length} candidates)`);\n\n // Filter to Tier 1 and applicable Tier 2 mappings\n const tier1Mappings = mappings.filter(m => m.tier === 1);\n const tier2Mappings = mappings.filter(m => m.tier === 2 && shouldApplyTier2(m, classification));\n\n // Prefer Tier 1 if available (always safe)\n if (tier1Mappings.length === 1) {\n logger.debug(`Resolved collision: using Tier 1 mapping \"${tier1Mappings[0].correctText}\"`);\n return tier1Mappings[0];\n }\n\n // If multiple Tier 1 mappings, this is ambiguous (shouldn't happen in practice)\n if (tier1Mappings.length > 1) {\n logger.warn(`Multiple Tier 1 mappings for \"${soundsLike}\", skipping replacement`);\n return null;\n }\n\n // Try Tier 2 mappings that match classification\n if (tier2Mappings.length === 1) {\n logger.debug(`Resolved collision: using Tier 2 mapping \"${tier2Mappings[0].correctText}\"`);\n return tier2Mappings[0];\n }\n\n // If multiple Tier 2 mappings match, this is ambiguous\n if (tier2Mappings.length > 1) {\n logger.debug(`Multiple Tier 2 mappings match for \"${soundsLike}\", skipping replacement`);\n return null;\n }\n\n // No applicable mappings\n logger.debug(`No applicable mappings for collision \"${soundsLike}\"`);\n return null;\n };\n\n /**\n * Detect capitalization hints in surrounding text\n */\n const detectCapitalizationHint = (\n soundsLike: string,\n surroundingText: string\n ): 'proper-noun' | 'common-term' | 'unknown' => {\n if (!useCapitalizationHints || !surroundingText) {\n return 'unknown';\n }\n\n // Find the sounds_like in the surrounding text\n const regex = new RegExp(`\\\\b${soundsLike}\\\\b`, 'i');\n const match = surroundingText.match(regex);\n\n if (!match) {\n return 'unknown';\n }\n\n const matchedText = match[0];\n\n // Check if it's capitalized\n const isCapitalized = matchedText[0] === matchedText[0].toUpperCase();\n\n if (!isCapitalized) {\n // Lowercase in text → likely common term\n return 'common-term';\n }\n\n // Capitalized - check if it's at sentence start\n const indexInText = surroundingText.indexOf(matchedText);\n\n // Look back for sentence boundaries\n const beforeText = surroundingText.substring(0, indexInText).trimEnd();\n const isAtSentenceStart = beforeText.length === 0 || /[.!?]\\s*$/.test(beforeText);\n\n if (isAtSentenceStart) {\n // Capitalized at sentence start → ambiguous\n return 'unknown';\n }\n\n // Capitalized mid-sentence → likely proper noun\n return 'proper-noun';\n };\n\n /**\n * Decide whether to apply a replacement\n */\n const decideReplacement = (context: CollisionContext): ReplacementDecision => {\n const { classification, soundsLike, availableMappings, surroundingText } = context;\n\n // No mappings available\n if (availableMappings.length === 0) {\n return {\n shouldReplace: false,\n reason: 'No mappings available',\n confidence: 1.0,\n };\n }\n\n // Single mapping - straightforward\n if (availableMappings.length === 1) {\n const mapping = availableMappings[0];\n\n // Tier 1: Always apply\n if (mapping.tier === 1) {\n return {\n shouldReplace: true,\n mapping,\n reason: 'Tier 1 mapping (always safe)',\n confidence: 1.0,\n };\n }\n\n // Tier 2: Check conditions\n if (mapping.tier === 2) {\n if (shouldApplyTier2(mapping, classification)) {\n return {\n shouldReplace: true,\n mapping,\n reason: `Tier 2 mapping (project: ${classification.project}, confidence: ${classification.confidence})`,\n confidence: classification.confidence ?? 0.5,\n };\n } else {\n return {\n shouldReplace: false,\n reason: 'Tier 2 conditions not met',\n confidence: 0.5,\n };\n }\n }\n\n // Tier 3: Skip\n return {\n shouldReplace: false,\n reason: 'Tier 3 mapping (too ambiguous)',\n confidence: 1.0,\n };\n }\n\n // Multiple mappings - collision scenario\n const resolvedMapping = resolveCollision(\n { soundsLike, mappings: availableMappings, count: availableMappings.length },\n classification\n );\n\n if (resolvedMapping) {\n return {\n shouldReplace: true,\n mapping: resolvedMapping,\n reason: `Collision resolved (${availableMappings.length} candidates)`,\n confidence: classification.confidence ?? 0.5,\n };\n }\n\n // Use capitalization hint as fallback (future enhancement)\n if (surroundingText && useCapitalizationHints) {\n const hint = detectCapitalizationHint(soundsLike, surroundingText);\n\n if (hint === 'common-term') {\n return {\n shouldReplace: false,\n reason: 'Capitalization hint suggests common term',\n confidence: 0.7,\n };\n }\n }\n\n // Could not resolve collision\n return {\n shouldReplace: false,\n reason: 'Collision could not be resolved',\n confidence: 0.5,\n };\n };\n\n return {\n decideReplacement,\n shouldApplyTier2,\n resolveCollision,\n detectCapitalizationHint,\n };\n};\n"],"names":["Logging.getLogger"],"mappings":"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"}
|