@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
package/dist/index30.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { getLogger } from './index41.js';
|
|
2
|
+
|
|
3
|
+
const create = (reasoning, context, config) => {
|
|
4
|
+
const logger = getLogger();
|
|
5
|
+
const analyze = async (feedback) => {
|
|
6
|
+
logger.info("Analyzing feedback for: %s", feedback.transcriptPath);
|
|
7
|
+
const allProjects = context.getAllProjects();
|
|
8
|
+
const projectSummary = allProjects.map((p) => ({
|
|
9
|
+
id: p.id,
|
|
10
|
+
name: p.name,
|
|
11
|
+
phrases: p.classification?.explicit_phrases || [],
|
|
12
|
+
topics: p.classification?.topics || [],
|
|
13
|
+
contextType: p.classification?.context_type,
|
|
14
|
+
destination: p.routing?.destination
|
|
15
|
+
}));
|
|
16
|
+
const prompt = `You are analyzing why a transcription routing system made a classification error.
|
|
17
|
+
|
|
18
|
+
## Original Classification Decision
|
|
19
|
+
- **Chosen Project**: ${feedback.originalDecision.projectId || "none (default routing)"}
|
|
20
|
+
- **Destination**: ${feedback.originalDecision.destination}
|
|
21
|
+
- **Confidence**: ${(feedback.originalDecision.confidence * 100).toFixed(1)}%
|
|
22
|
+
- **System's Reasoning**: ${feedback.originalDecision.reasoning}
|
|
23
|
+
|
|
24
|
+
## User's Correction
|
|
25
|
+
- **Correct Project**: ${feedback.correction.projectId || "not specified"}
|
|
26
|
+
- **Correct Destination**: ${feedback.correction.destination || "not specified"}
|
|
27
|
+
- **Topics**: ${feedback.correction.topics?.join(", ") || "not specified"}
|
|
28
|
+
- **Context Type**: ${feedback.correction.contextType || "not specified"}
|
|
29
|
+
|
|
30
|
+
## User's Explanation
|
|
31
|
+
"${feedback.userReason}"
|
|
32
|
+
|
|
33
|
+
## Current Project Context
|
|
34
|
+
${JSON.stringify(projectSummary, null, 2)}
|
|
35
|
+
|
|
36
|
+
## Your Task
|
|
37
|
+
Analyze why the classification failed and suggest specific updates to the context system.
|
|
38
|
+
|
|
39
|
+
Return a JSON object with:
|
|
40
|
+
1. "diagnosis": A clear explanation of what went wrong
|
|
41
|
+
2. "suggestedUpdates": Array of updates to make, each with:
|
|
42
|
+
- "type": "new_project" | "new_phrase" | "new_topic" | "context_type" | "association"
|
|
43
|
+
- "entityType": "project" | "person" | "company" | "term"
|
|
44
|
+
- "entityId": The entity to update (or new ID if creating)
|
|
45
|
+
- "changes": Array of { "field": string, "newValue": any }
|
|
46
|
+
- "reasoning": Why this update helps
|
|
47
|
+
- "confidence": 0-1 how confident you are
|
|
48
|
+
3. "clarificationQuestions": Optional questions if more info needed
|
|
49
|
+
4. "confidence": Overall confidence in this analysis (0-1)
|
|
50
|
+
|
|
51
|
+
Focus on:
|
|
52
|
+
- Missing trigger phrases that should match the correct project
|
|
53
|
+
- Topics that should be associated with projects
|
|
54
|
+
- Context type mismatches (work vs personal)
|
|
55
|
+
- New projects that need to be created
|
|
56
|
+
|
|
57
|
+
Respond with ONLY the JSON object.`;
|
|
58
|
+
try {
|
|
59
|
+
const response = await reasoning.complete({
|
|
60
|
+
systemPrompt: "You are an expert at analyzing classification systems and suggesting improvements. Always respond with valid JSON.",
|
|
61
|
+
prompt
|
|
62
|
+
});
|
|
63
|
+
const analysis = JSON.parse(response.content);
|
|
64
|
+
logger.info("Feedback analysis complete: %d suggested updates", analysis.suggestedUpdates.length);
|
|
65
|
+
return analysis;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
logger.error("Failed to analyze feedback", { error });
|
|
68
|
+
return {
|
|
69
|
+
diagnosis: "Unable to analyze feedback automatically. Manual review recommended.",
|
|
70
|
+
suggestedUpdates: [],
|
|
71
|
+
confidence: 0
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const applyUpdates = async (updates) => {
|
|
76
|
+
logger.info("Applying %d context updates", updates.length);
|
|
77
|
+
for (const update of updates) {
|
|
78
|
+
if (update.confidence < config.autoApplyThreshold) {
|
|
79
|
+
logger.info(
|
|
80
|
+
"Skipping low-confidence update: %s (%.1f%% < %.1f%%)",
|
|
81
|
+
update.entityId,
|
|
82
|
+
update.confidence * 100,
|
|
83
|
+
config.autoApplyThreshold * 100
|
|
84
|
+
);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
if (update.type === "new_project") {
|
|
89
|
+
const classification = {
|
|
90
|
+
context_type: "work",
|
|
91
|
+
explicit_phrases: [],
|
|
92
|
+
topics: []
|
|
93
|
+
};
|
|
94
|
+
const newProject = {
|
|
95
|
+
id: update.entityId,
|
|
96
|
+
name: update.entityId,
|
|
97
|
+
type: "project",
|
|
98
|
+
description: update.reasoning,
|
|
99
|
+
classification,
|
|
100
|
+
routing: {
|
|
101
|
+
// No destination - will use global default
|
|
102
|
+
structure: "month",
|
|
103
|
+
filename_options: ["date", "time", "subject"]
|
|
104
|
+
},
|
|
105
|
+
active: true
|
|
106
|
+
};
|
|
107
|
+
for (const change of update.changes) {
|
|
108
|
+
if (change.field === "name") newProject.name = String(change.newValue);
|
|
109
|
+
if (change.field === "destination") newProject.routing.destination = String(change.newValue);
|
|
110
|
+
if (change.field === "context_type") {
|
|
111
|
+
newProject.classification.context_type = change.newValue;
|
|
112
|
+
}
|
|
113
|
+
if (change.field === "explicit_phrases") {
|
|
114
|
+
newProject.classification.explicit_phrases = change.newValue;
|
|
115
|
+
}
|
|
116
|
+
if (change.field === "topics") {
|
|
117
|
+
newProject.classification.topics = change.newValue;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
await context.saveEntity(newProject);
|
|
121
|
+
logger.info("Created new project: %s", update.entityId);
|
|
122
|
+
} else if (update.type === "new_phrase" || update.type === "new_topic" || update.type === "context_type") {
|
|
123
|
+
const existing = context.getProject(update.entityId);
|
|
124
|
+
if (!existing) {
|
|
125
|
+
logger.warn("Project not found for update: %s", update.entityId);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const updated = { ...existing };
|
|
129
|
+
for (const change of update.changes) {
|
|
130
|
+
if (change.field === "explicit_phrases") {
|
|
131
|
+
const newPhrases = change.newValue;
|
|
132
|
+
updated.classification = {
|
|
133
|
+
...updated.classification,
|
|
134
|
+
explicit_phrases: [
|
|
135
|
+
...updated.classification?.explicit_phrases || [],
|
|
136
|
+
...newPhrases.filter(
|
|
137
|
+
(p) => !updated.classification?.explicit_phrases?.includes(p)
|
|
138
|
+
)
|
|
139
|
+
]
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (change.field === "topics") {
|
|
143
|
+
const newTopics = change.newValue;
|
|
144
|
+
updated.classification = {
|
|
145
|
+
...updated.classification,
|
|
146
|
+
topics: [
|
|
147
|
+
...updated.classification?.topics || [],
|
|
148
|
+
...newTopics.filter(
|
|
149
|
+
(t) => !updated.classification?.topics?.includes(t)
|
|
150
|
+
)
|
|
151
|
+
]
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (change.field === "context_type") {
|
|
155
|
+
updated.classification = {
|
|
156
|
+
...updated.classification,
|
|
157
|
+
context_type: change.newValue
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
await context.saveEntity(updated);
|
|
162
|
+
logger.info("Updated project: %s", update.entityId);
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
logger.error("Failed to apply update", { update, error });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
return { analyze, applyUpdates };
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export { create };
|
|
173
|
+
//# sourceMappingURL=index30.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index30.js","sources":["../src/feedback/analyzer.ts"],"sourcesContent":["/**\n * Feedback Analyzer\n * \n * Uses a reasoning model to analyze user feedback on classification\n * decisions and suggest context updates.\n */\n\nimport { ClassificationFeedback, FeedbackAnalysis, LearningUpdate } from './types';\nimport * as Reasoning from '../reasoning';\nimport * as Context from '@redaksjon/context';\nimport * as Logging from '../logging';\n\nexport interface AnalyzerInstance {\n analyze(feedback: ClassificationFeedback): Promise<FeedbackAnalysis>;\n applyUpdates(updates: LearningUpdate[]): Promise<void>;\n}\n\nexport interface AnalyzerConfig {\n model: string;\n autoApplyThreshold: number;\n}\n\nexport const create = (\n reasoning: Reasoning.ReasoningInstance,\n context: Context.ContextInstance,\n config: AnalyzerConfig\n): AnalyzerInstance => {\n const logger = Logging.getLogger();\n\n const analyze = async (feedback: ClassificationFeedback): Promise<FeedbackAnalysis> => {\n logger.info('Analyzing feedback for: %s', feedback.transcriptPath);\n\n // Gather current context for the model to understand\n const allProjects = context.getAllProjects();\n const projectSummary = allProjects.map(p => ({\n id: p.id,\n name: p.name,\n phrases: p.classification?.explicit_phrases || [],\n topics: p.classification?.topics || [],\n contextType: p.classification?.context_type,\n destination: p.routing?.destination,\n }));\n\n const prompt = `You are analyzing why a transcription routing system made a classification error.\n\n## Original Classification Decision\n- **Chosen Project**: ${feedback.originalDecision.projectId || 'none (default routing)'}\n- **Destination**: ${feedback.originalDecision.destination}\n- **Confidence**: ${(feedback.originalDecision.confidence * 100).toFixed(1)}%\n- **System's Reasoning**: ${feedback.originalDecision.reasoning}\n\n## User's Correction\n- **Correct Project**: ${feedback.correction.projectId || 'not specified'}\n- **Correct Destination**: ${feedback.correction.destination || 'not specified'}\n- **Topics**: ${feedback.correction.topics?.join(', ') || 'not specified'}\n- **Context Type**: ${feedback.correction.contextType || 'not specified'}\n\n## User's Explanation\n\"${feedback.userReason}\"\n\n## Current Project Context\n${JSON.stringify(projectSummary, null, 2)}\n\n## Your Task\nAnalyze why the classification failed and suggest specific updates to the context system.\n\nReturn a JSON object with:\n1. \"diagnosis\": A clear explanation of what went wrong\n2. \"suggestedUpdates\": Array of updates to make, each with:\n - \"type\": \"new_project\" | \"new_phrase\" | \"new_topic\" | \"context_type\" | \"association\"\n - \"entityType\": \"project\" | \"person\" | \"company\" | \"term\"\n - \"entityId\": The entity to update (or new ID if creating)\n - \"changes\": Array of { \"field\": string, \"newValue\": any }\n - \"reasoning\": Why this update helps\n - \"confidence\": 0-1 how confident you are\n3. \"clarificationQuestions\": Optional questions if more info needed\n4. \"confidence\": Overall confidence in this analysis (0-1)\n\nFocus on:\n- Missing trigger phrases that should match the correct project\n- Topics that should be associated with projects\n- Context type mismatches (work vs personal)\n- New projects that need to be created\n\nRespond with ONLY the JSON object.`;\n\n try {\n const response = await reasoning.complete({\n systemPrompt: 'You are an expert at analyzing classification systems and suggesting improvements. Always respond with valid JSON.',\n prompt,\n });\n\n // Parse the response\n const analysis = JSON.parse(response.content) as FeedbackAnalysis;\n logger.info('Feedback analysis complete: %d suggested updates', analysis.suggestedUpdates.length);\n\n return analysis;\n } catch (error) {\n logger.error('Failed to analyze feedback', { error });\n \n // Return a basic analysis if reasoning fails\n return {\n diagnosis: 'Unable to analyze feedback automatically. Manual review recommended.',\n suggestedUpdates: [],\n confidence: 0,\n };\n }\n };\n\n const applyUpdates = async (updates: LearningUpdate[]): Promise<void> => {\n logger.info('Applying %d context updates', updates.length);\n\n for (const update of updates) {\n // Skip low-confidence updates unless auto-apply threshold is 0\n if (update.confidence < config.autoApplyThreshold) {\n logger.info('Skipping low-confidence update: %s (%.1f%% < %.1f%%)',\n update.entityId, \n update.confidence * 100, \n config.autoApplyThreshold * 100\n );\n continue;\n }\n\n try {\n if (update.type === 'new_project') {\n // Create new project\n const classification: {\n context_type: 'work' | 'personal' | 'mixed';\n explicit_phrases: string[];\n topics: string[];\n } = {\n context_type: 'work',\n explicit_phrases: [],\n topics: [],\n };\n \n const newProject: {\n id: string;\n name: string;\n type: 'project';\n description: string;\n classification: typeof classification;\n routing: {\n destination?: string;\n structure: 'none' | 'year' | 'month' | 'day';\n filename_options: Array<'date' | 'time' | 'subject'>;\n };\n active: boolean;\n } = {\n id: update.entityId,\n name: update.entityId,\n type: 'project' as const,\n description: update.reasoning,\n classification,\n routing: {\n // No destination - will use global default\n structure: 'month' as const,\n filename_options: ['date', 'time', 'subject'] as Array<'date' | 'time' | 'subject'>,\n },\n active: true,\n };\n\n // Apply changes\n for (const change of update.changes) {\n if (change.field === 'name') newProject.name = String(change.newValue);\n if (change.field === 'destination') newProject.routing.destination = String(change.newValue);\n if (change.field === 'context_type') {\n newProject.classification.context_type = change.newValue as 'work' | 'personal' | 'mixed';\n }\n if (change.field === 'explicit_phrases') {\n newProject.classification.explicit_phrases = change.newValue as string[];\n }\n if (change.field === 'topics') {\n newProject.classification.topics = change.newValue as string[];\n }\n }\n\n await context.saveEntity(newProject);\n logger.info('Created new project: %s', update.entityId);\n\n } else if (update.type === 'new_phrase' || update.type === 'new_topic' || update.type === 'context_type') {\n // Update existing project\n const existing = context.getProject(update.entityId);\n if (!existing) {\n logger.warn('Project not found for update: %s', update.entityId);\n continue;\n }\n\n // Create updated entity\n const updated = { ...existing };\n \n for (const change of update.changes) {\n if (change.field === 'explicit_phrases') {\n const newPhrases = change.newValue as string[];\n updated.classification = {\n ...updated.classification,\n explicit_phrases: [\n ...(updated.classification?.explicit_phrases || []),\n ...newPhrases.filter(p => \n !updated.classification?.explicit_phrases?.includes(p)\n ),\n ],\n };\n }\n if (change.field === 'topics') {\n const newTopics = change.newValue as string[];\n updated.classification = {\n ...updated.classification,\n topics: [\n ...(updated.classification?.topics || []),\n ...newTopics.filter(t => \n !updated.classification?.topics?.includes(t)\n ),\n ],\n };\n }\n if (change.field === 'context_type') {\n updated.classification = {\n ...updated.classification,\n context_type: change.newValue as 'work' | 'personal' | 'mixed',\n };\n }\n }\n\n await context.saveEntity(updated);\n logger.info('Updated project: %s', update.entityId);\n }\n } catch (error) {\n logger.error('Failed to apply update', { update, error });\n }\n }\n };\n\n return { analyze, applyUpdates };\n};\n\n"],"names":["Logging.getLogger"],"mappings":"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"}
|
package/dist/index31.js
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import * as Context from '@redaksjon/context';
|
|
2
|
+
import { create as create$1 } from './index6.js';
|
|
3
|
+
import { create as create$2 } from './index53.js';
|
|
4
|
+
import { create as create$3 } from './index11.js';
|
|
5
|
+
import { create as create$4 } from './index3.js';
|
|
6
|
+
import { create as create$5 } from './index2.js';
|
|
7
|
+
import { create as create$7 } from './index5.js';
|
|
8
|
+
import { create as create$6 } from './index35.js';
|
|
9
|
+
import { getLogger } from './index41.js';
|
|
10
|
+
import { extractTagsFromSignals, createRoutingMetadata } from './index14.js';
|
|
11
|
+
|
|
12
|
+
const create = async (config) => {
|
|
13
|
+
const logger = getLogger();
|
|
14
|
+
const currentWorkingDir = globalThis.process.cwd();
|
|
15
|
+
logger.debug("Initializing intelligent transcription pipeline...");
|
|
16
|
+
const context = await Context.create({
|
|
17
|
+
startingDir: config.contextDirectory || currentWorkingDir,
|
|
18
|
+
contextDirectories: config.contextDirectories
|
|
19
|
+
});
|
|
20
|
+
logger.debug("Context system initialized - ready to query entities via tools");
|
|
21
|
+
const defaultPath = config.outputDirectory || "~/notes";
|
|
22
|
+
const defaultStructure = config.outputStructure || "month";
|
|
23
|
+
const defaultFilenameOptions = config.outputFilenameOptions || ["date", "time", "subject"];
|
|
24
|
+
const contextProjects = context.getAllProjects();
|
|
25
|
+
const routingProjects = contextProjects.filter((project) => project.active !== false).map((project) => ({
|
|
26
|
+
projectId: project.id,
|
|
27
|
+
destination: {
|
|
28
|
+
path: project.routing?.destination || defaultPath,
|
|
29
|
+
structure: project.routing?.structure || defaultStructure,
|
|
30
|
+
filename_options: project.routing?.filename_options || defaultFilenameOptions,
|
|
31
|
+
createDirectories: true
|
|
32
|
+
},
|
|
33
|
+
classification: project.classification,
|
|
34
|
+
active: project.active,
|
|
35
|
+
auto_tags: project.routing?.auto_tags
|
|
36
|
+
}));
|
|
37
|
+
logger.debug("Loaded %d projects from context for routing", routingProjects.length);
|
|
38
|
+
const routingConfig = {
|
|
39
|
+
default: {
|
|
40
|
+
path: defaultPath,
|
|
41
|
+
structure: defaultStructure,
|
|
42
|
+
filename_options: defaultFilenameOptions,
|
|
43
|
+
createDirectories: true
|
|
44
|
+
},
|
|
45
|
+
projects: routingProjects,
|
|
46
|
+
conflict_resolution: "primary"
|
|
47
|
+
};
|
|
48
|
+
const routing = create$1(routingConfig, context);
|
|
49
|
+
logger.debug("Routing system initialized");
|
|
50
|
+
const output = create$2({
|
|
51
|
+
intermediateDir: config.intermediateDir || "./output/protokoll",
|
|
52
|
+
keepIntermediates: config.keepIntermediates ?? true});
|
|
53
|
+
logger.debug("Output manager initialized");
|
|
54
|
+
const reflection = config.selfReflection ? create$3({
|
|
55
|
+
format: "markdown",
|
|
56
|
+
includeConversation: false,
|
|
57
|
+
includeOutput: true
|
|
58
|
+
}) : null;
|
|
59
|
+
if (reflection) {
|
|
60
|
+
logger.debug("Self-reflection system enabled");
|
|
61
|
+
}
|
|
62
|
+
const transcription = create$4({
|
|
63
|
+
defaultModel: config.transcriptionModel
|
|
64
|
+
});
|
|
65
|
+
logger.debug("Transcription service initialized with model: %s", config.transcriptionModel);
|
|
66
|
+
const reasoning = create$5({
|
|
67
|
+
model: config.model,
|
|
68
|
+
reasoningLevel: config.reasoningLevel
|
|
69
|
+
});
|
|
70
|
+
logger.debug("Reasoning system initialized with model: %s, reasoning level: %s", config.model, config.reasoningLevel || "medium");
|
|
71
|
+
const complete = config.processedDirectory ? create$6({
|
|
72
|
+
processedDirectory: config.processedDirectory,
|
|
73
|
+
outputStructure: config.outputStructure,
|
|
74
|
+
dryRun: config.dryRun
|
|
75
|
+
}) : null;
|
|
76
|
+
if (complete) {
|
|
77
|
+
logger.debug("Complete phase initialized with processed directory: %s", config.processedDirectory);
|
|
78
|
+
}
|
|
79
|
+
const extractTitleFromPath = (outputPath) => {
|
|
80
|
+
const filename = outputPath.split("/").pop()?.replace(".md", "");
|
|
81
|
+
if (!filename) return void 0;
|
|
82
|
+
const withoutDate = filename.replace(/^\d{2}-\d{4}-/, "");
|
|
83
|
+
if (!withoutDate) return void 0;
|
|
84
|
+
return withoutDate.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
85
|
+
};
|
|
86
|
+
const isMeaningfulTitle = (title) => {
|
|
87
|
+
if (!title) return false;
|
|
88
|
+
const stripped = title.replace(/\s+/g, "");
|
|
89
|
+
const numberRatio = (stripped.match(/\d/g) || []).length / stripped.length;
|
|
90
|
+
if (numberRatio > 0.5) return false;
|
|
91
|
+
if (stripped.length < 3) return false;
|
|
92
|
+
const badPatterns = /^(i|i have|i am|the|a|an|um|uh|so|well|okay|oh|hey|hi)$/i;
|
|
93
|
+
if (badPatterns.test(title.trim())) return false;
|
|
94
|
+
return true;
|
|
95
|
+
};
|
|
96
|
+
const generateTitleFromContent = async (transcriptText, fallbackTitle) => {
|
|
97
|
+
try {
|
|
98
|
+
const textSample = transcriptText.slice(0, 2e3);
|
|
99
|
+
const response = await reasoning.complete({
|
|
100
|
+
systemPrompt: `You are a title generator. Given a transcript, generate a concise, descriptive title (3-8 words) that captures the main topic or theme.
|
|
101
|
+
|
|
102
|
+
Rules:
|
|
103
|
+
- Output ONLY the title, nothing else
|
|
104
|
+
- No quotes around the title
|
|
105
|
+
- Use Title Case
|
|
106
|
+
- Be specific - avoid generic titles like "Meeting Notes" or "Discussion"
|
|
107
|
+
- Focus on the main subject matter
|
|
108
|
+
- If there are multiple topics, pick the most prominent one`,
|
|
109
|
+
prompt: `Generate a title for this transcript:
|
|
110
|
+
|
|
111
|
+
${textSample}`
|
|
112
|
+
});
|
|
113
|
+
const title = response.content.trim().replace(/^["']|["']$/g, "").replace(/^#\s*/, "").trim();
|
|
114
|
+
if (title && title.length > 0 && title.length < 100) {
|
|
115
|
+
logger.debug("Generated title from content: %s", title);
|
|
116
|
+
return title;
|
|
117
|
+
}
|
|
118
|
+
logger.debug("Generated title was invalid, using fallback");
|
|
119
|
+
return fallbackTitle || "Untitled";
|
|
120
|
+
} catch (error) {
|
|
121
|
+
logger.warn("Title generation failed, using fallback", { error });
|
|
122
|
+
return fallbackTitle || "Untitled";
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const processInput = async (input) => {
|
|
126
|
+
const startTime = Date.now();
|
|
127
|
+
const progressPrefix = input.progress ? `[${input.progress.current}/${input.progress.total}]` : "";
|
|
128
|
+
const log = (level, message, ...args) => {
|
|
129
|
+
const prefixedMessage = progressPrefix ? `${progressPrefix} ${message}` : message;
|
|
130
|
+
if (level === "info") {
|
|
131
|
+
logger.info(prefixedMessage, ...args);
|
|
132
|
+
} else {
|
|
133
|
+
logger.debug(prefixedMessage, ...args);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
log("info", "Processing: %s (hash: %s)", input.audioFile, input.hash);
|
|
137
|
+
const state = {
|
|
138
|
+
input,
|
|
139
|
+
startTime: /* @__PURE__ */ new Date()
|
|
140
|
+
};
|
|
141
|
+
if (reflection) {
|
|
142
|
+
reflection.collector.start();
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
log("debug", "Checking onboarding state...");
|
|
146
|
+
const onboardingState = { needsOnboarding: false };
|
|
147
|
+
if (onboardingState.needsOnboarding) ;
|
|
148
|
+
log("info", "Transcribing audio...");
|
|
149
|
+
const whisperStart = Date.now();
|
|
150
|
+
const transcriptionResult = await transcription.transcribe(input.audioFile, {
|
|
151
|
+
model: config.transcriptionModel
|
|
152
|
+
});
|
|
153
|
+
state.rawTranscript = transcriptionResult.text;
|
|
154
|
+
const whisperDuration = Date.now() - whisperStart;
|
|
155
|
+
log(
|
|
156
|
+
"info",
|
|
157
|
+
"Transcription: %d chars in %.1fs",
|
|
158
|
+
state.rawTranscript.length,
|
|
159
|
+
whisperDuration / 1e3
|
|
160
|
+
);
|
|
161
|
+
if (reflection) {
|
|
162
|
+
reflection.collector.recordWhisper(whisperDuration);
|
|
163
|
+
}
|
|
164
|
+
log("debug", "Determining routing destination...");
|
|
165
|
+
const routingContext = {
|
|
166
|
+
transcriptText: state.rawTranscript || "",
|
|
167
|
+
audioDate: input.creation,
|
|
168
|
+
sourceFile: input.audioFile,
|
|
169
|
+
hash: input.hash
|
|
170
|
+
};
|
|
171
|
+
const routeResult = routing.route(routingContext);
|
|
172
|
+
log(
|
|
173
|
+
"debug",
|
|
174
|
+
"Routing decision: project=%s, confidence=%.2f",
|
|
175
|
+
routeResult.projectId || "default",
|
|
176
|
+
routeResult.confidence
|
|
177
|
+
);
|
|
178
|
+
if (reflection) {
|
|
179
|
+
reflection.collector.recordRoutingDecision({
|
|
180
|
+
projectId: routeResult.projectId,
|
|
181
|
+
destination: routeResult.destination.path,
|
|
182
|
+
confidence: routeResult.confidence,
|
|
183
|
+
reasoning: routeResult.reasoning,
|
|
184
|
+
signals: routeResult.signals.map((s) => ({
|
|
185
|
+
type: s.type,
|
|
186
|
+
value: s.value,
|
|
187
|
+
weight: s.weight
|
|
188
|
+
})),
|
|
189
|
+
alternativesConsidered: routeResult.alternateMatches?.map((alt) => ({
|
|
190
|
+
projectId: alt.projectId,
|
|
191
|
+
confidence: alt.confidence,
|
|
192
|
+
whyNotChosen: `Lower confidence (${(alt.confidence * 100).toFixed(1)}%)`
|
|
193
|
+
}))
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
const outputPath = routing.buildOutputPath(routeResult, routingContext);
|
|
197
|
+
log("debug", "Output path: %s", outputPath);
|
|
198
|
+
log("debug", "Setting up output directories...");
|
|
199
|
+
const paths = output.createOutputPaths(
|
|
200
|
+
input.audioFile,
|
|
201
|
+
outputPath,
|
|
202
|
+
input.hash,
|
|
203
|
+
input.creation
|
|
204
|
+
);
|
|
205
|
+
await output.ensureDirectories(paths);
|
|
206
|
+
await output.writeIntermediate(paths, "transcript", {
|
|
207
|
+
text: state.rawTranscript,
|
|
208
|
+
model: config.transcriptionModel,
|
|
209
|
+
duration: whisperDuration
|
|
210
|
+
});
|
|
211
|
+
log("info", "Enhancing with %s...", config.model);
|
|
212
|
+
const agenticStart = Date.now();
|
|
213
|
+
const toolContext = {
|
|
214
|
+
transcriptText: state.rawTranscript || "",
|
|
215
|
+
audioDate: input.creation,
|
|
216
|
+
sourceFile: input.audioFile,
|
|
217
|
+
contextInstance: context,
|
|
218
|
+
routingInstance: routing,
|
|
219
|
+
interactiveMode: config.interactive
|
|
220
|
+
// Interactive moved to protokoll-cli
|
|
221
|
+
// interactiveInstance: interactive,
|
|
222
|
+
};
|
|
223
|
+
const executor = create$7(reasoning, toolContext);
|
|
224
|
+
const agenticResult = await executor.process(state.rawTranscript || "");
|
|
225
|
+
state.enhancedText = agenticResult.enhancedText;
|
|
226
|
+
const toolsUsed = agenticResult.toolsUsed;
|
|
227
|
+
const agenticDuration = Date.now() - agenticStart;
|
|
228
|
+
if (reflection) {
|
|
229
|
+
for (const tool of toolsUsed) {
|
|
230
|
+
reflection.collector.recordToolCall(tool, agenticDuration / toolsUsed.length, true);
|
|
231
|
+
}
|
|
232
|
+
reflection.collector.recordCorrection(state.rawTranscript || "", state.enhancedText);
|
|
233
|
+
if (agenticResult.totalTokens) {
|
|
234
|
+
reflection.collector.recordModelResponse(config.model, agenticResult.totalTokens);
|
|
235
|
+
}
|
|
236
|
+
if (agenticResult.contextChanges) {
|
|
237
|
+
for (const change of agenticResult.contextChanges) {
|
|
238
|
+
reflection.collector.recordContextChange(change);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
await output.writeIntermediate(paths, "session", {
|
|
243
|
+
iterations: agenticResult.iterations,
|
|
244
|
+
toolsUsed: agenticResult.toolsUsed,
|
|
245
|
+
state: agenticResult.state
|
|
246
|
+
});
|
|
247
|
+
if (agenticResult.state.routeDecision?.destination?.path) {
|
|
248
|
+
const agenticRoute = agenticResult.state.routeDecision;
|
|
249
|
+
log(
|
|
250
|
+
"debug",
|
|
251
|
+
"Agentic processing found route: %s -> %s",
|
|
252
|
+
agenticRoute.projectId || "unknown",
|
|
253
|
+
agenticRoute.destination.path
|
|
254
|
+
);
|
|
255
|
+
routeResult.projectId = agenticRoute.projectId || routeResult.projectId;
|
|
256
|
+
routeResult.destination = {
|
|
257
|
+
...routeResult.destination,
|
|
258
|
+
path: agenticRoute.destination.path,
|
|
259
|
+
structure: agenticRoute.destination.structure || routeResult.destination.structure
|
|
260
|
+
};
|
|
261
|
+
routeResult.confidence = agenticRoute.confidence || routeResult.confidence;
|
|
262
|
+
routeResult.reasoning = agenticRoute.reasoning || routeResult.reasoning;
|
|
263
|
+
if (agenticRoute.signals) {
|
|
264
|
+
routeResult.signals = agenticRoute.signals;
|
|
265
|
+
}
|
|
266
|
+
const newOutputPath = routing.buildOutputPath(routeResult, routingContext);
|
|
267
|
+
log("debug", "Updated output path: %s -> %s", outputPath, newOutputPath);
|
|
268
|
+
const newPaths = output.createOutputPaths(
|
|
269
|
+
input.audioFile,
|
|
270
|
+
newOutputPath,
|
|
271
|
+
input.hash,
|
|
272
|
+
input.creation
|
|
273
|
+
);
|
|
274
|
+
await output.ensureDirectories(newPaths);
|
|
275
|
+
Object.assign(paths, newPaths);
|
|
276
|
+
}
|
|
277
|
+
log("debug", "Writing raw transcript to .transcript/ directory...");
|
|
278
|
+
await output.writeRawTranscript(paths, {
|
|
279
|
+
text: state.rawTranscript,
|
|
280
|
+
model: config.transcriptionModel,
|
|
281
|
+
duration: whisperDuration,
|
|
282
|
+
audioFile: input.audioFile,
|
|
283
|
+
audioHash: input.hash,
|
|
284
|
+
transcribedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
285
|
+
});
|
|
286
|
+
log("debug", "Writing final transcript...");
|
|
287
|
+
if (state.enhancedText) {
|
|
288
|
+
const buildEntityReferences = () => {
|
|
289
|
+
const refs = agenticResult.state.referencedEntities;
|
|
290
|
+
if (!refs) return void 0;
|
|
291
|
+
const entities = {
|
|
292
|
+
people: [],
|
|
293
|
+
projects: [],
|
|
294
|
+
terms: [],
|
|
295
|
+
companies: []
|
|
296
|
+
};
|
|
297
|
+
for (const personId of refs.people) {
|
|
298
|
+
const person = context.getPerson(personId);
|
|
299
|
+
if (person) {
|
|
300
|
+
entities.people.push({ id: person.id, name: person.name, type: "person" });
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
for (const projectId of refs.projects) {
|
|
304
|
+
const project = context.getProject(projectId);
|
|
305
|
+
if (project) {
|
|
306
|
+
entities.projects.push({ id: project.id, name: project.name, type: "project" });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
for (const termId of refs.terms) {
|
|
310
|
+
const term = context.getTerm(termId);
|
|
311
|
+
if (term) {
|
|
312
|
+
entities.terms.push({ id: term.id, name: term.name, type: "term" });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
for (const companyId of refs.companies) {
|
|
316
|
+
const company = context.getCompany(companyId);
|
|
317
|
+
if (company) {
|
|
318
|
+
entities.companies.push({ id: company.id, name: company.name, type: "company" });
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
const hasEntities = entities.people.length > 0 || entities.projects.length > 0 || entities.terms.length > 0 || entities.companies.length > 0;
|
|
322
|
+
return hasEntities ? entities : void 0;
|
|
323
|
+
};
|
|
324
|
+
const pathTitle = extractTitleFromPath(paths.final);
|
|
325
|
+
let title;
|
|
326
|
+
if (isMeaningfulTitle(pathTitle)) {
|
|
327
|
+
title = pathTitle;
|
|
328
|
+
} else {
|
|
329
|
+
log("debug", "Path-derived title not meaningful (%s), generating from content...", pathTitle || "empty");
|
|
330
|
+
title = await generateTitleFromContent(state.enhancedText, pathTitle);
|
|
331
|
+
log("info", "Generated title: %s", title);
|
|
332
|
+
const contextWithTitle = {
|
|
333
|
+
...routingContext,
|
|
334
|
+
subjectOverride: title
|
|
335
|
+
};
|
|
336
|
+
const newOutputPath = routing.buildOutputPath(routeResult, contextWithTitle);
|
|
337
|
+
if (newOutputPath !== paths.final) {
|
|
338
|
+
log("debug", "Updating output path with generated title: %s -> %s", paths.final, newOutputPath);
|
|
339
|
+
const newPaths = output.createOutputPaths(
|
|
340
|
+
input.audioFile,
|
|
341
|
+
newOutputPath,
|
|
342
|
+
input.hash,
|
|
343
|
+
input.creation
|
|
344
|
+
);
|
|
345
|
+
await output.ensureDirectories(newPaths);
|
|
346
|
+
Object.assign(paths, newPaths);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const transcriptMetadata = {
|
|
350
|
+
title,
|
|
351
|
+
projectId: routeResult.projectId || void 0,
|
|
352
|
+
project: routeResult.projectId || void 0,
|
|
353
|
+
date: input.creation,
|
|
354
|
+
routing: createRoutingMetadata(routeResult),
|
|
355
|
+
tags: extractTagsFromSignals(routeResult.signals),
|
|
356
|
+
confidence: routeResult.confidence,
|
|
357
|
+
entities: buildEntityReferences()
|
|
358
|
+
};
|
|
359
|
+
await output.writeTranscript(paths, state.enhancedText, transcriptMetadata);
|
|
360
|
+
}
|
|
361
|
+
log("debug", "Generating reflection report...");
|
|
362
|
+
let reflectionReport;
|
|
363
|
+
if (reflection) {
|
|
364
|
+
reflectionReport = reflection.generate(
|
|
365
|
+
input.audioFile,
|
|
366
|
+
paths.final,
|
|
367
|
+
void 0,
|
|
368
|
+
state.enhancedText
|
|
369
|
+
);
|
|
370
|
+
if (paths.intermediate.reflection) {
|
|
371
|
+
await reflection.save(reflectionReport, paths.intermediate.reflection);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
log("debug", "Finalizing session...");
|
|
375
|
+
if (!config.keepIntermediates && !config.debug) {
|
|
376
|
+
await output.cleanIntermediates(paths);
|
|
377
|
+
}
|
|
378
|
+
let processedAudioPath;
|
|
379
|
+
if (complete) {
|
|
380
|
+
const subject = paths.final.split("/").pop()?.replace(".md", "") || void 0;
|
|
381
|
+
processedAudioPath = await complete.complete(
|
|
382
|
+
input.audioFile,
|
|
383
|
+
input.hash,
|
|
384
|
+
input.creation,
|
|
385
|
+
subject
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
const processingTime = Date.now() - startTime;
|
|
389
|
+
log(
|
|
390
|
+
"info",
|
|
391
|
+
"Enhancement: %d iterations, %d tools, %.1fs",
|
|
392
|
+
agenticResult.iterations,
|
|
393
|
+
toolsUsed.length,
|
|
394
|
+
agenticDuration / 1e3
|
|
395
|
+
);
|
|
396
|
+
if (agenticResult.totalTokens) {
|
|
397
|
+
log("info", "Tokens: %d total", agenticResult.totalTokens);
|
|
398
|
+
}
|
|
399
|
+
log("info", "Output: %s (%.1fs total)", paths.final, processingTime / 1e3);
|
|
400
|
+
return {
|
|
401
|
+
outputPath: paths.final,
|
|
402
|
+
enhancedText: state.enhancedText || "",
|
|
403
|
+
rawTranscript: state.rawTranscript || "",
|
|
404
|
+
routedProject: routeResult.projectId,
|
|
405
|
+
routingConfidence: routeResult.confidence,
|
|
406
|
+
processingTime,
|
|
407
|
+
toolsUsed,
|
|
408
|
+
correctionsApplied: agenticResult.state.resolvedEntities.size,
|
|
409
|
+
processedAudioPath,
|
|
410
|
+
reflection: reflectionReport,
|
|
411
|
+
// session, // Interactive moved to protokoll-cli
|
|
412
|
+
intermediatePaths: paths
|
|
413
|
+
};
|
|
414
|
+
} catch (error) {
|
|
415
|
+
logger.error("Pipeline error", { error });
|
|
416
|
+
throw error;
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
return { process: processInput };
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
export { create };
|
|
423
|
+
//# sourceMappingURL=index31.js.map
|