@redaksjon/protokoll-engine 0.1.3 → 0.1.4-dev.20260216151443.e1454c9

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.
Files changed (163) hide show
  1. package/dist/agentic/executor.d.ts.map +1 -1
  2. package/dist/agentic/types.d.ts +4 -1
  3. package/dist/agentic/types.d.ts.map +1 -1
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +8 -5
  7. package/dist/index.js.map +1 -1
  8. package/dist/index10.js +4 -3
  9. package/dist/index10.js.map +1 -1
  10. package/dist/index11.js +2 -2
  11. package/dist/index12.js +3 -124
  12. package/dist/index12.js.map +1 -1
  13. package/dist/index13.js +101 -100
  14. package/dist/index13.js.map +1 -1
  15. package/dist/index14.js +109 -281
  16. package/dist/index14.js.map +1 -1
  17. package/dist/index15.js +285 -89
  18. package/dist/index15.js.map +1 -1
  19. package/dist/index16.js +97 -104
  20. package/dist/index16.js.map +1 -1
  21. package/dist/index17.js +18 -179
  22. package/dist/index17.js.map +1 -1
  23. package/dist/index18.js +102 -48
  24. package/dist/index18.js.map +1 -1
  25. package/dist/index19.js +182 -16
  26. package/dist/index19.js.map +1 -1
  27. package/dist/index2.js +3 -3
  28. package/dist/index20.js +48 -100
  29. package/dist/index20.js.map +1 -1
  30. package/dist/index21.js +16 -23
  31. package/dist/index21.js.map +1 -1
  32. package/dist/index22.js +98 -42
  33. package/dist/index22.js.map +1 -1
  34. package/dist/index23.js +19 -112
  35. package/dist/index23.js.map +1 -1
  36. package/dist/index24.js +42 -323
  37. package/dist/index24.js.map +1 -1
  38. package/dist/index25.js +114 -52
  39. package/dist/index25.js.map +1 -1
  40. package/dist/index26.js +339 -37
  41. package/dist/index26.js.map +1 -1
  42. package/dist/index27.js +51 -121
  43. package/dist/index27.js.map +1 -1
  44. package/dist/index28.js +36 -155
  45. package/dist/index28.js.map +1 -1
  46. package/dist/index29.js +114 -150
  47. package/dist/index29.js.map +1 -1
  48. package/dist/index3.js +2 -2
  49. package/dist/index30.js +171 -161
  50. package/dist/index30.js.map +1 -1
  51. package/dist/index31.js +141 -401
  52. package/dist/index31.js.map +1 -1
  53. package/dist/index32.js +158 -146
  54. package/dist/index32.js.map +1 -1
  55. package/dist/index33.js +425 -130
  56. package/dist/index33.js.map +1 -1
  57. package/dist/index34.js +145 -40
  58. package/dist/index34.js.map +1 -1
  59. package/dist/index35.js +159 -83
  60. package/dist/index35.js.map +1 -1
  61. package/dist/index36.js +46 -439
  62. package/dist/index36.js.map +1 -1
  63. package/dist/index37.js +91 -419
  64. package/dist/index37.js.map +1 -1
  65. package/dist/index38.js +447 -66
  66. package/dist/index38.js.map +1 -1
  67. package/dist/index39.js +424 -115
  68. package/dist/index39.js.map +1 -1
  69. package/dist/index4.js +2 -2
  70. package/dist/index40.js +78 -290
  71. package/dist/index40.js.map +1 -1
  72. package/dist/index41.js +112 -44
  73. package/dist/index41.js.map +1 -1
  74. package/dist/index42.js +115 -44
  75. package/dist/index42.js.map +1 -1
  76. package/dist/index43.js +295 -35
  77. package/dist/index43.js.map +1 -1
  78. package/dist/index44.js +270 -218
  79. package/dist/index44.js.map +1 -1
  80. package/dist/index45.js +131 -150
  81. package/dist/index45.js.map +1 -1
  82. package/dist/index46.js +117 -73
  83. package/dist/index46.js.map +1 -1
  84. package/dist/index47.js +45 -74
  85. package/dist/index47.js.map +1 -1
  86. package/dist/index48.js +48 -5
  87. package/dist/index48.js.map +1 -1
  88. package/dist/index49.js +33 -145
  89. package/dist/index49.js.map +1 -1
  90. package/dist/index5.js +3 -3
  91. package/dist/index50.js +216 -203
  92. package/dist/index50.js.map +1 -1
  93. package/dist/index51.js +153 -39
  94. package/dist/index51.js.map +1 -1
  95. package/dist/index52.js +74 -38
  96. package/dist/index52.js.map +1 -1
  97. package/dist/index53.js +74 -33
  98. package/dist/index53.js.map +1 -1
  99. package/dist/index54.js +149 -6
  100. package/dist/index54.js.map +1 -1
  101. package/dist/index55.js +224 -6
  102. package/dist/index55.js.map +1 -1
  103. package/dist/index56.js +42 -143
  104. package/dist/index56.js.map +1 -1
  105. package/dist/index57.js +43 -15
  106. package/dist/index57.js.map +1 -1
  107. package/dist/index58.js +35 -2
  108. package/dist/index58.js.map +1 -1
  109. package/dist/index59.js +5 -14
  110. package/dist/index59.js.map +1 -1
  111. package/dist/index6.js +4 -4
  112. package/dist/index6.js.map +1 -1
  113. package/dist/index60.js +6 -2
  114. package/dist/index60.js.map +1 -1
  115. package/dist/index61.js +6 -4
  116. package/dist/index61.js.map +1 -1
  117. package/dist/index62.js +151 -0
  118. package/dist/index62.js.map +1 -0
  119. package/dist/index63.js +17 -0
  120. package/dist/index63.js.map +1 -0
  121. package/dist/index64.js +4 -0
  122. package/dist/index64.js.map +1 -0
  123. package/dist/index65.js +17 -0
  124. package/dist/index65.js.map +1 -0
  125. package/dist/index66.js +4 -0
  126. package/dist/index66.js.map +1 -0
  127. package/dist/index67.js +6 -0
  128. package/dist/index67.js.map +1 -0
  129. package/dist/index7.js +2 -2
  130. package/dist/index8.js +1 -1
  131. package/dist/index9.js +4 -4
  132. package/dist/phases/simple-replace.d.ts +2 -1
  133. package/dist/phases/simple-replace.d.ts.map +1 -1
  134. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  135. package/dist/pipeline/types.d.ts +3 -0
  136. package/dist/pipeline/types.d.ts.map +1 -1
  137. package/dist/routing/classifier.d.ts +2 -1
  138. package/dist/routing/classifier.d.ts.map +1 -1
  139. package/dist/routing/index.d.ts +2 -1
  140. package/dist/routing/index.d.ts.map +1 -1
  141. package/dist/routing/types.d.ts +1 -1
  142. package/dist/routing/types.d.ts.map +1 -1
  143. package/dist/transcript/index.d.ts +1 -0
  144. package/dist/transcript/index.d.ts.map +1 -1
  145. package/dist/transcript/operations.d.ts +14 -1
  146. package/dist/transcript/operations.d.ts.map +1 -1
  147. package/dist/transcript/upload-utils.d.ts +80 -0
  148. package/dist/transcript/upload-utils.d.ts.map +1 -0
  149. package/dist/util/enhancement-logger.d.ts +19 -0
  150. package/dist/util/enhancement-logger.d.ts.map +1 -0
  151. package/dist/util/metadata.d.ts +1 -0
  152. package/dist/util/metadata.d.ts.map +1 -1
  153. package/dist/weighting/builder.d.ts +126 -0
  154. package/dist/weighting/builder.d.ts.map +1 -0
  155. package/dist/weighting/index.d.ts +12 -0
  156. package/dist/weighting/index.d.ts.map +1 -0
  157. package/dist/weighting/prepositioning.d.ts +55 -0
  158. package/dist/weighting/prepositioning.d.ts.map +1 -0
  159. package/dist/weighting/provider.d.ts +78 -0
  160. package/dist/weighting/provider.d.ts.map +1 -0
  161. package/dist/weighting/types.d.ts +119 -0
  162. package/dist/weighting/types.d.ts.map +1 -0
  163. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"index41.js","sources":["../src/logging.ts"],"sourcesContent":["import winston from 'winston';\nimport { DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES_SECONDS, PROGRAM_NAME } from './constants';\n\nexport interface LogContext {\n [key: string]: any;\n}\n\nconst createLogger = (level: string = 'info') => {\n\n let format = winston.format.combine(\n winston.format.timestamp({ format: DATE_FORMAT_YEAR_MONTH_DAY_HOURS_MINUTES_SECONDS }),\n winston.format.errors({ stack: true }),\n winston.format.splat(),\n winston.format.json()\n );\n\n let transports = [\n new winston.transports.Console({\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.printf(({ timestamp, level, message, ...meta }) => {\n const metaStr = Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : '';\n return `${timestamp} ${level}: ${message}${metaStr}`;\n })\n )\n })\n ];\n\n if (level === 'info') {\n format = winston.format.combine(\n winston.format.errors({ stack: true }),\n winston.format.splat(),\n );\n\n transports = [\n new winston.transports.Console({\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.printf(({ level, message }) => {\n return `${level}: ${message}`;\n })\n )\n })\n ];\n }\n\n return winston.createLogger({\n level,\n format,\n defaultMeta: { service: PROGRAM_NAME },\n transports,\n });\n};\n\nlet logger = createLogger();\n\nexport const setLogLevel = (level: string) => {\n logger = createLogger(level);\n};\n\nexport const getLogger = () => logger; "],"names":["level"],"mappings":";;;AAOA,MAAM,YAAA,GAAe,CAAC,KAAA,GAAgB,MAAA,KAAW;AAE7C,EAAA,IAAI,MAAA,GAAS,QAAQ,MAAA,CAAO,OAAA;AAAA,IACxB,QAAQ,MAAA,CAAO,SAAA,CAAU,EAAE,MAAA,EAAQ,kDAAkD,CAAA;AAAA,IACrF,QAAQ,MAAA,CAAO,MAAA,CAAO,EAAE,KAAA,EAAO,MAAM,CAAA;AAAA,IACrC,OAAA,CAAQ,OAAO,KAAA,EAAM;AAAA,IACrB,OAAA,CAAQ,OAAO,IAAA;AAAK,GACxB;AAEA,EAAA,IAAI,UAAA,GAAa;AAAA,IACb,IAAI,OAAA,CAAQ,UAAA,CAAW,OAAA,CAAQ;AAAA,MAC3B,MAAA,EAAQ,QAAQ,MAAA,CAAO,OAAA;AAAA,QACnB,OAAA,CAAQ,OAAO,QAAA,EAAS;AAAA,QACxB,OAAA,CAAQ,MAAA,CAAO,MAAA,CAAO,CAAC,EAAE,SAAA,EAAW,KAAA,EAAAA,MAAAA,EAAO,OAAA,EAAS,GAAG,IAAA,EAAK,KAAM;AAC9D,UAAA,MAAM,OAAA,GAAU,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,MAAA,GAAS,CAAA,CAAA,EAAI,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA,CAAA,GAAK,EAAA;AACxE,UAAA,OAAO,GAAG,SAAS,CAAA,CAAA,EAAIA,MAAK,CAAA,EAAA,EAAK,OAAO,GAAG,OAAO,CAAA,CAAA;AAAA,QACtD,CAAC;AAAA;AACL,KACH;AAAA,GACL;AAEA,EAAA,IAAI,UAAU,MAAA,EAAQ;AAClB,IAAA,MAAA,GAAS,QAAQ,MAAA,CAAO,OAAA;AAAA,MACpB,QAAQ,MAAA,CAAO,MAAA,CAAO,EAAE,KAAA,EAAO,MAAM,CAAA;AAAA,MACrC,OAAA,CAAQ,OAAO,KAAA;AAAM,KACzB;AAEA,IAAA,UAAA,GAAa;AAAA,MACT,IAAI,OAAA,CAAQ,UAAA,CAAW,OAAA,CAAQ;AAAA,QAC3B,MAAA,EAAQ,QAAQ,MAAA,CAAO,OAAA;AAAA,UACnB,OAAA,CAAQ,OAAO,QAAA,EAAS;AAAA,UACxB,OAAA,CAAQ,OAAO,MAAA,CAAO,CAAC,EAAE,KAAA,EAAAA,MAAAA,EAAO,SAAQ,KAAM;AAC1C,YAAA,OAAO,CAAA,EAAGA,MAAK,CAAA,EAAA,EAAK,OAAO,CAAA,CAAA;AAAA,UAC/B,CAAC;AAAA;AACL,OACH;AAAA,KACL;AAAA,EACJ;AAEA,EAAA,OAAO,QAAQ,YAAA,CAAa;AAAA,IACxB,KAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA,EAAa,EAAE,OAAA,EAAS,YAAA,EAAa;AAAA,IACrC;AAAA,GACH,CAAA;AACL,CAAA;AAEA,IAAI,SAAS,YAAA,EAAa;AAMnB,MAAM,YAAY,MAAM;;;;"}
1
+ {"version":3,"file":"index41.js","sources":["../src/transcript/upload-utils.ts"],"sourcesContent":["/**\n * Upload workflow utilities for audio transcription\n * \n * Handles creation of transcript records for uploaded audio files\n * and queue scanning for files awaiting transcription.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { join } from 'node:path';\nimport { glob } from 'glob';\nimport { PklTranscript } from '@redaksjon/protokoll-format';\nimport type { TranscriptMetadata } from '@redaksjon/protokoll-format';\n\n/**\n * Parameters for creating an upload transcript\n */\nexport interface CreateUploadTranscriptParams {\n audioFile: string; // Path to uploaded audio file\n originalFilename: string; // Original uploaded filename\n audioHash: string; // File hash for deduplication\n outputDirectory: string; // Where to create PKL\n title?: string; // Optional title hint\n project?: string; // Optional project hint\n}\n\n/**\n * Generate a UUID-prefixed filename\n * Format: {8-char-uuid}-{basename}.pkl\n */\nexport function generateFilenameWithUuid(uuid: string, basename: string): string {\n // Take first 8 characters of UUID\n const prefix = uuid.substring(0, 8);\n // Remove .pkl extension from basename if present\n const base = basename.replace(/\\.pkl$/, '');\n return `${prefix}-${base}.pkl`;\n}\n\n/**\n * Format timestamp for filename\n */\nfunction formatTimestamp(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hour = String(date.getHours()).padStart(2, '0');\n const minute = String(date.getMinutes()).padStart(2, '0');\n const second = String(date.getSeconds()).padStart(2, '0');\n return `${year}${month}${day}-${hour}${minute}${second}`;\n}\n\n/**\n * Create a transcript record for an uploaded audio file\n * \n * Creates a PKL file with 'uploaded' status and UUID-prefixed filename.\n * This makes the transcript discoverable via findTranscriptByUuid().\n * \n * @param params - Upload transcript parameters\n * @returns UUID and file path of created transcript\n */\nexport async function createUploadTranscript(\n params: CreateUploadTranscriptParams\n): Promise<{ uuid: string; filePath: string }> {\n const uuid = randomUUID();\n const timestamp = formatTimestamp(new Date());\n \n // Use UUID-prefixed filename for uploads\n const filename = generateFilenameWithUuid(uuid, `${timestamp}-upload.pkl`);\n const filePath = join(params.outputDirectory, filename);\n \n const metadata: TranscriptMetadata = {\n id: uuid,\n status: 'uploaded',\n audioFile: params.originalFilename,\n audioHash: params.audioHash,\n date: new Date(),\n title: params.title,\n project: params.project,\n };\n \n const transcript = PklTranscript.create(filePath, metadata);\n await transcript.close();\n \n return { uuid, filePath };\n}\n\n/**\n * Result from scanning for uploaded transcripts\n */\nexport interface UploadedTranscript {\n uuid: string;\n filePath: string;\n metadata: TranscriptMetadata;\n}\n\n/**\n * Find all transcripts in 'uploaded' status ready for transcription\n * \n * Scans directories for PKL files with UUID prefixes and 'uploaded' status.\n * Results are sorted by date (oldest first) for FIFO processing.\n * \n * @param searchDirectories - Directories to scan for transcripts\n * @returns Array of uploaded transcripts sorted by date\n */\nexport async function findUploadedTranscripts(\n searchDirectories: string[]\n): Promise<UploadedTranscript[]> {\n const results: UploadedTranscript[] = [];\n \n for (const dir of searchDirectories) {\n // Find all PKL files with UUID prefixes (8 hex chars followed by dash)\n const files = await glob('????????-*.pkl', { cwd: dir, absolute: true });\n \n for (const file of files) {\n try {\n const transcript = PklTranscript.open(file, { readOnly: true });\n const metadata = transcript.metadata;\n \n if (metadata.status === 'uploaded') {\n results.push({ \n uuid: metadata.id, \n filePath: file, \n metadata \n });\n }\n \n await transcript.close();\n } catch (error) {\n // Skip files that can't be opened (corrupted, locked, etc.)\n // eslint-disable-next-line no-console\n console.warn(`Failed to open transcript ${file}:`, error);\n }\n }\n }\n \n // Sort by date (oldest first) for FIFO processing\n return results.sort((a, b) => {\n const aTime = a.metadata.date?.getTime() || 0;\n const bTime = b.metadata.date?.getTime() || 0;\n return aTime - bTime;\n });\n}\n\n/**\n * Find transcripts in 'transcribing' status (for recovery after crash)\n * \n * These transcripts were being processed when the server stopped.\n * They should be reset to 'uploaded' and re-queued.\n * \n * @param searchDirectories - Directories to scan for transcripts\n * @returns Array of transcribing transcripts\n */\nexport async function findTranscribingTranscripts(\n searchDirectories: string[]\n): Promise<UploadedTranscript[]> {\n const results: UploadedTranscript[] = [];\n \n for (const dir of searchDirectories) {\n const files = await glob('????????-*.pkl', { cwd: dir, absolute: true });\n \n for (const file of files) {\n try {\n const transcript = PklTranscript.open(file, { readOnly: true });\n const metadata = transcript.metadata;\n \n if (metadata.status === 'transcribing') {\n results.push({ \n uuid: metadata.id, \n filePath: file, \n metadata \n });\n }\n \n await transcript.close();\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Failed to open transcript ${file}:`, error);\n }\n }\n }\n \n return results;\n}\n\n/**\n * Reset a transcript from 'transcribing' or 'error' to 'uploaded' for retry\n * \n * Used during queue recovery on server startup or manual retry.\n * \n * @param filePath - Path to transcript file\n */\nexport async function resetTranscriptToUploaded(filePath: string): Promise<void> {\n const transcript = PklTranscript.open(filePath);\n const metadata = transcript.metadata;\n \n if (metadata.status === 'transcribing' || metadata.status === 'error') {\n transcript.updateMetadata({ \n status: 'uploaded',\n errorDetails: undefined, // Clear error details on retry\n });\n await transcript.close();\n } else {\n await transcript.close();\n }\n}\n\n/**\n * Mark a transcript as transcribing (in progress)\n * \n * @param filePath - Path to transcript file\n */\nexport async function markTranscriptAsTranscribing(filePath: string): Promise<void> {\n const transcript = PklTranscript.open(filePath);\n transcript.updateMetadata({ status: 'transcribing' });\n await transcript.close();\n}\n\n/**\n * Mark a transcript as failed with error details\n * \n * @param filePath - Path to transcript file\n * @param errorDetails - Error message/details\n */\nexport async function markTranscriptAsFailed(\n filePath: string, \n errorDetails: string\n): Promise<void> {\n const transcript = PklTranscript.open(filePath);\n transcript.updateMetadata({ \n status: 'error',\n errorDetails \n });\n await transcript.close();\n}\n"],"names":[],"mappings":"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"}
package/dist/index42.js CHANGED
@@ -1,51 +1,122 @@
1
- import { OpenAI } from 'openai';
2
- import { create } from './index12.js';
3
- import { getLogger } from './index41.js';
4
- import { DEFAULT_TRANSCRIPTION_MODEL } from './index16.js';
1
+ import { getLogger } from './index47.js';
5
2
 
6
- class OpenAIError extends Error {
7
- constructor(message) {
8
- super(message);
9
- this.name = "OpenAIError";
10
- }
11
- }
12
- async function transcribeAudio(filePath, options = {}) {
3
+ const create = () => {
13
4
  const logger = getLogger();
14
- const storage$1 = create({ log: logger.debug });
15
- try {
16
- const apiKey = process.env.OPENAI_API_KEY;
17
- if (!apiKey) {
18
- throw new OpenAIError("OPENAI_API_KEY environment variable is not set");
5
+ let startTime = /* @__PURE__ */ new Date();
6
+ let whisperDuration = 0;
7
+ let iterations = 0;
8
+ let originalLength = 0;
9
+ let correctedLength = 0;
10
+ let correctionsApplied = 0;
11
+ let model = "";
12
+ let tokensUsed = 0;
13
+ const unknownEntities = [];
14
+ const resolvedEntities = /* @__PURE__ */ new Map();
15
+ const toolCalls = /* @__PURE__ */ new Map();
16
+ const contextChanges = [];
17
+ let routingDecision;
18
+ const start = () => {
19
+ startTime = /* @__PURE__ */ new Date();
20
+ logger.debug("Reflection collector started");
21
+ };
22
+ const recordWhisper = (duration) => {
23
+ whisperDuration = duration;
24
+ };
25
+ const recordToolCall = (name, duration, success) => {
26
+ iterations++;
27
+ if (!toolCalls.has(name)) {
28
+ toolCalls.set(name, { count: 0, successCount: 0, totalDuration: 0 });
19
29
  }
20
- const openai = new OpenAI({
21
- apiKey
22
- });
23
- const model = options.model || DEFAULT_TRANSCRIPTION_MODEL;
24
- const fileName = filePath.split("/").pop() || filePath;
25
- logger.debug("Transcribing: %s (full path: %s)", fileName, filePath);
26
- const startTime = Date.now();
27
- const audioStream = await storage$1.readStream(filePath);
28
- const transcription = await openai.audio.transcriptions.create({
29
- model,
30
- file: audioStream,
31
- response_format: "json"
32
- });
33
- if (!transcription) {
34
- throw new OpenAIError("No transcription received from OpenAI");
30
+ const stats = toolCalls.get(name);
31
+ stats.count++;
32
+ stats.totalDuration += duration;
33
+ if (success) {
34
+ stats.successCount++;
35
35
  }
36
- const duration = ((Date.now() - startTime) / 1e3).toFixed(1);
37
- logger.info("%s (%ss, %d chars)", model, duration, transcription.text?.length || 0);
38
- if (options.debug && options.debugFile) {
39
- await storage$1.writeFile(options.debugFile, JSON.stringify(transcription, null, 2), "utf8");
40
- logger.debug("Wrote debug file to %s", options.debugFile);
36
+ };
37
+ const recordCorrection = (original, corrected) => {
38
+ if (originalLength === 0) {
39
+ originalLength = original.length;
41
40
  }
42
- logger.debug("Received transcription from OpenAI: %s", transcription);
43
- return transcription;
44
- } catch (error) {
45
- logger.error("Error transcribing audio file: %s %s", error.message, error.stack);
46
- throw new OpenAIError(`Failed to transcribe audio: ${error.message}`);
47
- }
48
- }
41
+ correctedLength = corrected.length;
42
+ correctionsApplied++;
43
+ };
44
+ const recordUnknownEntity = (entity) => {
45
+ unknownEntities.push(entity);
46
+ };
47
+ const recordResolvedEntity = (entity, resolved) => {
48
+ resolvedEntities.set(entity, resolved);
49
+ };
50
+ const recordModelResponse = (m, tokens) => {
51
+ model = m;
52
+ tokensUsed += tokens;
53
+ };
54
+ const recordContextChange = (change) => {
55
+ contextChanges.push(change);
56
+ logger.info('Context change recorded: %s %s "%s"', change.action, change.entityType, change.entityName);
57
+ };
58
+ const getContextChanges = () => {
59
+ return [...contextChanges];
60
+ };
61
+ const recordRoutingDecision = (decision) => {
62
+ routingDecision = decision;
63
+ logger.debug(
64
+ "Routing decision recorded: project=%s, confidence=%.1f%%",
65
+ decision.projectId || "default",
66
+ decision.confidence * 100
67
+ );
68
+ };
69
+ const getRoutingDecision = () => {
70
+ return routingDecision;
71
+ };
72
+ const getMetrics = () => {
73
+ const endTime = /* @__PURE__ */ new Date();
74
+ const totalDuration = endTime.getTime() - startTime.getTime();
75
+ const reasoningDuration = totalDuration - whisperDuration;
76
+ return {
77
+ startTime,
78
+ endTime,
79
+ totalDuration,
80
+ whisperDuration,
81
+ reasoningDuration,
82
+ iterations,
83
+ toolCallsExecuted: Array.from(toolCalls.values()).reduce((sum, t) => sum + t.count, 0),
84
+ toolsUsed: Array.from(toolCalls.keys()),
85
+ originalLength,
86
+ correctedLength,
87
+ correctionsApplied,
88
+ unknownEntitiesFound: unknownEntities.length,
89
+ entitiesResolved: resolvedEntities.size,
90
+ model,
91
+ tokensUsed
92
+ };
93
+ };
94
+ const getToolEffectiveness = () => {
95
+ return Array.from(toolCalls.entries()).map(([name, stats]) => ({
96
+ name,
97
+ callCount: stats.count,
98
+ successCount: stats.successCount,
99
+ failureCount: stats.count - stats.successCount,
100
+ avgDuration: stats.count > 0 ? stats.totalDuration / stats.count : 0,
101
+ successRate: stats.count > 0 ? stats.successCount / stats.count : 0
102
+ }));
103
+ };
104
+ return {
105
+ start,
106
+ recordWhisper,
107
+ recordToolCall,
108
+ recordCorrection,
109
+ recordUnknownEntity,
110
+ recordResolvedEntity,
111
+ recordModelResponse,
112
+ recordContextChange,
113
+ recordRoutingDecision,
114
+ getMetrics,
115
+ getToolEffectiveness,
116
+ getContextChanges,
117
+ getRoutingDecision
118
+ };
119
+ };
49
120
 
50
- export { OpenAIError, transcribeAudio };
121
+ export { create };
51
122
  //# sourceMappingURL=index42.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index42.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;;;;"}
1
+ {"version":3,"file":"index42.js","sources":["../src/reflection/collector.ts"],"sourcesContent":["/**\n * Metrics Collector\n *\n * Collects metrics during transcription for self-reflection reporting.\n */\n\nimport { TranscriptionMetrics, ToolEffectiveness, ContextChange, RoutingDecisionRecord } from './types';\nimport * as Logging from '../logging';\n\nexport interface CollectorInstance {\n start(): void;\n recordWhisper(duration: number): void;\n recordToolCall(name: string, duration: number, success: boolean): void;\n recordCorrection(original: string, corrected: string): void;\n recordUnknownEntity(entity: string): void;\n recordResolvedEntity(entity: string, resolved: string): void;\n recordModelResponse(model: string, tokens: number): void;\n recordContextChange(change: ContextChange): void;\n recordRoutingDecision(decision: RoutingDecisionRecord): void;\n getMetrics(): TranscriptionMetrics;\n getToolEffectiveness(): ToolEffectiveness[];\n getContextChanges(): ContextChange[];\n getRoutingDecision(): RoutingDecisionRecord | undefined;\n}\n\ninterface ToolStats {\n count: number;\n successCount: number;\n totalDuration: number;\n}\n\nexport const create = (): CollectorInstance => {\n const logger = Logging.getLogger();\n \n let startTime: Date = new Date();\n let whisperDuration = 0;\n let iterations = 0;\n let originalLength = 0;\n let correctedLength = 0;\n let correctionsApplied = 0;\n let model = '';\n let tokensUsed = 0;\n \n const unknownEntities: string[] = [];\n const resolvedEntities: Map<string, string> = new Map();\n const toolCalls: Map<string, ToolStats> = new Map();\n const contextChanges: ContextChange[] = [];\n let routingDecision: RoutingDecisionRecord | undefined;\n \n const start = () => {\n startTime = new Date();\n logger.debug('Reflection collector started');\n };\n \n const recordWhisper = (duration: number) => {\n whisperDuration = duration;\n };\n \n const recordToolCall = (name: string, duration: number, success: boolean) => {\n iterations++;\n \n if (!toolCalls.has(name)) {\n toolCalls.set(name, { count: 0, successCount: 0, totalDuration: 0 });\n }\n \n const stats = toolCalls.get(name)!;\n stats.count++;\n stats.totalDuration += duration;\n if (success) {\n stats.successCount++;\n }\n };\n \n const recordCorrection = (original: string, corrected: string) => {\n if (originalLength === 0) {\n originalLength = original.length;\n }\n correctedLength = corrected.length;\n correctionsApplied++;\n };\n \n const recordUnknownEntity = (entity: string) => {\n unknownEntities.push(entity);\n };\n \n const recordResolvedEntity = (entity: string, resolved: string) => {\n resolvedEntities.set(entity, resolved);\n };\n \n const recordModelResponse = (m: string, tokens: number) => {\n model = m;\n tokensUsed += tokens;\n };\n \n const recordContextChange = (change: ContextChange) => {\n contextChanges.push(change);\n logger.info('Context change recorded: %s %s \"%s\"', change.action, change.entityType, change.entityName);\n };\n\n const getContextChanges = (): ContextChange[] => {\n return [...contextChanges];\n };\n\n const recordRoutingDecision = (decision: RoutingDecisionRecord) => {\n routingDecision = decision;\n logger.debug('Routing decision recorded: project=%s, confidence=%.1f%%', \n decision.projectId || 'default', decision.confidence * 100);\n };\n\n const getRoutingDecision = (): RoutingDecisionRecord | undefined => {\n return routingDecision;\n };\n \n const getMetrics = (): TranscriptionMetrics => {\n const endTime = new Date();\n const totalDuration = endTime.getTime() - startTime.getTime();\n const reasoningDuration = totalDuration - whisperDuration;\n \n return {\n startTime,\n endTime,\n totalDuration,\n whisperDuration,\n reasoningDuration,\n iterations,\n toolCallsExecuted: Array.from(toolCalls.values()).reduce((sum, t) => sum + t.count, 0),\n toolsUsed: Array.from(toolCalls.keys()),\n originalLength,\n correctedLength,\n correctionsApplied,\n unknownEntitiesFound: unknownEntities.length,\n entitiesResolved: resolvedEntities.size,\n model,\n tokensUsed,\n };\n };\n \n const getToolEffectiveness = (): ToolEffectiveness[] => {\n return Array.from(toolCalls.entries()).map(([name, stats]) => ({\n name,\n callCount: stats.count,\n successCount: stats.successCount,\n failureCount: stats.count - stats.successCount,\n avgDuration: stats.count > 0 ? stats.totalDuration / stats.count : 0,\n successRate: stats.count > 0 ? stats.successCount / stats.count : 0,\n }));\n };\n \n return {\n start,\n recordWhisper,\n recordToolCall,\n recordCorrection,\n recordUnknownEntity,\n recordResolvedEntity,\n recordModelResponse,\n recordContextChange,\n recordRoutingDecision,\n getMetrics,\n getToolEffectiveness,\n getContextChanges,\n getRoutingDecision,\n };\n};\n\n"],"names":["Logging.getLogger"],"mappings":"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"}
package/dist/index43.js CHANGED
@@ -1,39 +1,299 @@
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));
1
+ import * as fs from 'fs/promises';
2
+ import { getLogger } from './index47.js';
3
+
4
+ const create = (config) => {
5
+ const logger = getLogger();
6
+ const assessQuality = (metrics, toolEffectiveness) => {
7
+ const nameAccuracy = metrics.unknownEntitiesFound > 0 ? metrics.entitiesResolved / metrics.unknownEntitiesFound : 1;
8
+ const contentPreservation = metrics.originalLength > 0 ? Math.min(metrics.correctedLength / metrics.originalLength, 1) : 1;
9
+ const avgToolSuccess = toolEffectiveness.length > 0 ? toolEffectiveness.reduce((sum, t) => sum + t.successRate, 0) / toolEffectiveness.length : 1;
10
+ const confidence = nameAccuracy * 0.4 + contentPreservation * 0.3 + avgToolSuccess * 0.3;
11
+ return {
12
+ confidence,
13
+ nameAccuracy,
14
+ routingConfidence: 0.9,
15
+ // Would be calculated from routing decision
16
+ contentPreservation,
17
+ overallScore: confidence
18
+ };
19
+ };
20
+ const generateRecommendations = (metrics, toolEffectiveness, quality) => {
21
+ const recommendations = [];
22
+ const failedTools = toolEffectiveness.filter((t) => t.successRate < 0.8);
23
+ if (failedTools.length > 0) {
24
+ recommendations.push({
25
+ type: "tool-issue",
26
+ severity: "high",
27
+ message: `${failedTools.length} tool(s) had low success rates`,
28
+ suggestion: `Review tool implementations: ${failedTools.map((t) => t.name).join(", ")}`
29
+ });
30
+ }
31
+ if (metrics.unknownEntitiesFound > metrics.entitiesResolved) {
32
+ const unresolved = metrics.unknownEntitiesFound - metrics.entitiesResolved;
33
+ recommendations.push({
34
+ type: "context-gap",
35
+ severity: "medium",
36
+ message: `${unresolved} entities could not be resolved`,
37
+ suggestion: "Run in interactive mode to add new context entries"
38
+ });
39
+ }
40
+ if (metrics.iterations > 10) {
41
+ recommendations.push({
42
+ type: "context-gap",
43
+ severity: "medium",
44
+ message: `High iteration count (${metrics.iterations}) - model may be struggling to route this note`,
45
+ suggestion: 'Add explicit trigger phrases to your project context files (e.g., "update on [project]")'
46
+ });
47
+ }
48
+ if (metrics.totalDuration > 3e5) {
49
+ recommendations.push({
50
+ type: "performance",
51
+ severity: "low",
52
+ message: `Processing took ${(metrics.totalDuration / 1e3).toFixed(1)}s`,
53
+ suggestion: "Consider reviewing context files - unclear routing can cause excessive iterations"
54
+ });
55
+ }
56
+ if (quality.contentPreservation < 0.9) {
57
+ recommendations.push({
58
+ type: "quality",
59
+ severity: "high",
60
+ message: "Significant content may have been lost",
61
+ suggestion: "Review prompt to ensure full content preservation"
15
62
  });
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 "";
63
+ }
64
+ return recommendations;
65
+ };
66
+ const generate = (collector, audioFile, outputFile, conversationHistory, output) => {
67
+ const metrics = collector.getMetrics();
68
+ const toolEffectiveness = collector.getToolEffectiveness();
69
+ const contextChanges = collector.getContextChanges();
70
+ const routingDecision = collector.getRoutingDecision();
71
+ const quality = assessQuality(metrics, toolEffectiveness);
72
+ const recommendations = generateRecommendations(metrics, toolEffectiveness, quality);
73
+ return {
74
+ id: `reflection-${Date.now()}`,
75
+ generated: /* @__PURE__ */ new Date(),
76
+ audioFile,
77
+ outputFile,
78
+ summary: {
79
+ duration: metrics.totalDuration,
80
+ iterations: metrics.iterations,
81
+ toolCalls: metrics.toolCallsExecuted,
82
+ corrections: metrics.correctionsApplied,
83
+ confidence: quality.confidence
84
+ },
85
+ metrics,
86
+ toolEffectiveness,
87
+ quality,
88
+ recommendations,
89
+ routingDecision,
90
+ contextChanges: contextChanges.length > 0 ? contextChanges : void 0,
91
+ conversationHistory: config.includeConversation ? conversationHistory : void 0,
92
+ output: config.includeOutput ? output : void 0
93
+ };
94
+ };
95
+ const formatMarkdown = (report) => {
96
+ let md = `# Protokoll - Self-Reflection Report
97
+
98
+ `;
99
+ md += `**Generated:** ${report.generated.toISOString()}
100
+ `;
101
+ md += `**Audio File:** ${report.audioFile}
102
+ `;
103
+ md += `**Output:** ${report.outputFile}
104
+
105
+ `;
106
+ md += `## Summary
107
+
108
+ `;
109
+ md += `- **Duration**: ${(report.summary.duration / 1e3).toFixed(1)}s
110
+ `;
111
+ md += `- **Iterations**: ${report.summary.iterations}
112
+ `;
113
+ md += `- **Tool Calls**: ${report.summary.toolCalls}
114
+ `;
115
+ md += `- **Corrections**: ${report.summary.corrections}
116
+ `;
117
+ md += `- **Confidence**: ${(report.summary.confidence * 100).toFixed(1)}%
118
+
119
+ `;
120
+ md += `## Quality Assessment
121
+
122
+ `;
123
+ md += `- **Overall Score**: ${(report.quality.overallScore * 100).toFixed(1)}%
124
+ `;
125
+ md += `- **Name Accuracy**: ${(report.quality.nameAccuracy * 100).toFixed(1)}%
126
+ `;
127
+ md += `- **Content Preservation**: ${(report.quality.contentPreservation * 100).toFixed(1)}%
128
+ `;
129
+ md += `- **Routing Confidence**: ${(report.quality.routingConfidence * 100).toFixed(1)}%
130
+
131
+ `;
132
+ if (report.routingDecision) {
133
+ const rd = report.routingDecision;
134
+ md += `## Routing Decision
135
+
136
+ `;
137
+ md += `**Project**: ${rd.projectId || "(default routing)"}
138
+ `;
139
+ md += `**Destination**: \`${rd.destination}\`
140
+ `;
141
+ md += `**Confidence**: ${(rd.confidence * 100).toFixed(1)}%
142
+
143
+ `;
144
+ md += `### Reasoning
145
+
146
+ `;
147
+ md += `${rd.reasoning}
148
+
149
+ `;
150
+ if (rd.signals && rd.signals.length > 0) {
151
+ md += `### Classification Signals
152
+
153
+ `;
154
+ md += `| Signal Type | Value | Weight | Source |
155
+ `;
156
+ md += `|-------------|-------|--------|--------|
157
+ `;
158
+ for (const signal of rd.signals) {
159
+ const source = signal.source || "-";
160
+ md += `| ${signal.type} | "${signal.value}" | ${(signal.weight * 100).toFixed(0)}% | ${source} |
161
+ `;
162
+ }
163
+ md += "\n";
164
+ }
165
+ if (rd.alternativesConsidered && rd.alternativesConsidered.length > 0) {
166
+ md += `### Alternatives Considered
167
+
168
+ `;
169
+ for (const alt of rd.alternativesConsidered) {
170
+ md += `- **${alt.projectId}** (${(alt.confidence * 100).toFixed(1)}% confidence)
171
+ `;
172
+ md += ` - Not chosen because: ${alt.whyNotChosen}
173
+ `;
174
+ }
175
+ md += "\n";
176
+ }
177
+ if (rd.userConfirmed) {
178
+ md += `*User confirmed this routing decision in interactive mode.*
179
+
180
+ `;
181
+ }
182
+ if (rd.feedbackProvided) {
183
+ md += `### Feedback Received
184
+
185
+ `;
186
+ md += `This routing was later corrected: ${rd.feedbackCorrection}
187
+
188
+ `;
189
+ }
190
+ }
191
+ if (report.toolEffectiveness.length > 0) {
192
+ md += `## Tool Effectiveness
193
+
194
+ `;
195
+ md += `| Tool | Calls | Success | Failure | Success Rate | Avg Duration |
196
+ `;
197
+ md += `|------|-------|---------|---------|--------------|-------------|
198
+ `;
199
+ for (const tool of report.toolEffectiveness) {
200
+ md += `| ${tool.name} | ${tool.callCount} | ${tool.successCount} | ${tool.failureCount} | `;
201
+ md += `${(tool.successRate * 100).toFixed(1)}% | ${tool.avgDuration.toFixed(0)}ms |
202
+ `;
203
+ }
204
+ md += "\n";
205
+ }
206
+ if (report.recommendations.length > 0) {
207
+ md += `## Recommendations
208
+
209
+ `;
210
+ const bySeverity = {
211
+ high: report.recommendations.filter((r) => r.severity === "high"),
212
+ medium: report.recommendations.filter((r) => r.severity === "medium"),
213
+ low: report.recommendations.filter((r) => r.severity === "low")
214
+ };
215
+ if (bySeverity.high.length > 0) {
216
+ md += `### 🔴 High Priority
217
+
218
+ `;
219
+ bySeverity.high.forEach((rec, i) => {
220
+ md += `${i + 1}. **${rec.message}**
221
+ `;
222
+ if (rec.suggestion) md += ` - ${rec.suggestion}
223
+ `;
224
+ });
225
+ md += "\n";
226
+ }
227
+ if (bySeverity.medium.length > 0) {
228
+ md += `### 🟡 Medium Priority
229
+
230
+ `;
231
+ bySeverity.medium.forEach((rec, i) => {
232
+ md += `${i + 1}. **${rec.message}**
233
+ `;
234
+ if (rec.suggestion) md += ` - ${rec.suggestion}
235
+ `;
236
+ });
237
+ md += "\n";
238
+ }
239
+ if (bySeverity.low.length > 0) {
240
+ md += `### 🟢 Low Priority
241
+
242
+ `;
243
+ bySeverity.low.forEach((rec, i) => {
244
+ md += `${i + 1}. **${rec.message}**
245
+ `;
246
+ if (rec.suggestion) md += ` - ${rec.suggestion}
247
+ `;
248
+ });
249
+ md += "\n";
250
+ }
251
+ }
252
+ if (report.contextChanges && report.contextChanges.length > 0) {
253
+ md += `## Context Changes
254
+
255
+ `;
256
+ md += `The following context entries were created or updated during this session:
257
+
258
+ `;
259
+ for (const change of report.contextChanges) {
260
+ const emoji = change.action === "created" ? "✨" : "📝";
261
+ md += `${emoji} **${change.action.charAt(0).toUpperCase() + change.action.slice(1)} ${change.entityType}**: ${change.entityName}
262
+ `;
263
+ if (change.details) {
264
+ const details = change.details;
265
+ const routing = details.routing;
266
+ const destination = details.destination || routing?.destination;
267
+ if (destination) {
268
+ md += ` - Routing to: \`${destination}\`
269
+ `;
270
+ }
271
+ }
272
+ }
273
+ md += "\n";
274
+ }
275
+ md += `---
276
+
277
+ `;
278
+ md += `*Report generated by Protokoll Self-Reflection System*
279
+ `;
280
+ return md;
281
+ };
282
+ const formatJson = (report) => {
283
+ return JSON.stringify(report, null, 2);
284
+ };
285
+ const save = async (report, path) => {
286
+ const content = config.format === "markdown" ? formatMarkdown(report) : formatJson(report);
287
+ await fs.writeFile(path, content, "utf-8");
288
+ logger.info("Saved reflection report", { path });
289
+ };
290
+ return {
291
+ generate,
292
+ formatMarkdown,
293
+ formatJson,
294
+ save
295
+ };
36
296
  };
37
297
 
38
- export { stringifyJSON };
298
+ export { create };
39
299
  //# sourceMappingURL=index43.js.map