task-summary-extractor 9.2.0 → 9.2.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-summary-extractor",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.1",
|
|
4
4
|
"description": "AI-powered meeting analysis & document generation CLI — video + document processing, deep dive docs, dynamic mode, interactive CLI with model selection, confidence scoring, learning loop, git progress tracking",
|
|
5
5
|
"main": "process_and_upload.js",
|
|
6
6
|
"bin": {
|
package/src/phases/compile.js
CHANGED
|
@@ -8,7 +8,7 @@ const { compileFinalResult } = require('../services/gemini');
|
|
|
8
8
|
|
|
9
9
|
// --- Utils ---
|
|
10
10
|
const { calculateCompilationBudget } = require('../utils/adaptive-budget');
|
|
11
|
-
const { validateAnalysis, formatSchemaLine } = require('../utils/schema-validator');
|
|
11
|
+
const { validateAnalysis, formatSchemaLine, normalizeAnalysis } = require('../utils/schema-validator');
|
|
12
12
|
const { c } = require('../utils/colors');
|
|
13
13
|
|
|
14
14
|
// --- Shared state ---
|
|
@@ -41,7 +41,7 @@ async function phaseCompile(ctx, allSegmentAnalyses) {
|
|
|
41
41
|
{ thinkingBudget: compBudget.budget }
|
|
42
42
|
);
|
|
43
43
|
|
|
44
|
-
compiledAnalysis = compilationResult.compiled;
|
|
44
|
+
compiledAnalysis = normalizeAnalysis(compilationResult.compiled);
|
|
45
45
|
compilationRun = compilationResult.run;
|
|
46
46
|
|
|
47
47
|
// Track compilation cost
|
|
@@ -17,7 +17,7 @@ const { fmtDuration, fmtBytes } = require('../utils/format');
|
|
|
17
17
|
const { promptUser } = require('../utils/cli');
|
|
18
18
|
const { parallelMap } = require('../utils/retry');
|
|
19
19
|
const { assessQuality, formatQualityLine, getConfidenceStats, THRESHOLDS } = require('../utils/quality-gate');
|
|
20
|
-
const { validateAnalysis, formatSchemaLine, schemaScore } = require('../utils/schema-validator');
|
|
20
|
+
const { validateAnalysis, formatSchemaLine, schemaScore, normalizeAnalysis } = require('../utils/schema-validator');
|
|
21
21
|
const { calculateThinkingBudget } = require('../utils/adaptive-budget');
|
|
22
22
|
const { detectBoundaryContext, sliceVttForSegment } = require('../utils/context-manager');
|
|
23
23
|
|
|
@@ -264,7 +264,7 @@ async function phaseProcessVideo(ctx, videoPath, videoIndex) {
|
|
|
264
264
|
try {
|
|
265
265
|
const existingRun = JSON.parse(fs.readFileSync(latestRunPath, 'utf8'));
|
|
266
266
|
geminiRunFile = path.relative(PROJECT_ROOT, path.join(geminiRunsDir, latestRunFile));
|
|
267
|
-
analysis = existingRun.output.parsed || { rawResponse: existingRun.output.raw };
|
|
267
|
+
analysis = normalizeAnalysis(existingRun.output.parsed || { rawResponse: existingRun.output.raw });
|
|
268
268
|
analysis._geminiMeta = {
|
|
269
269
|
model: existingRun.run.model,
|
|
270
270
|
processedAt: existingRun.run.timestamp,
|
|
@@ -396,7 +396,7 @@ async function phaseProcessVideo(ctx, videoPath, videoIndex) {
|
|
|
396
396
|
geminiFileName = geminiRun.input.videoFile.geminiFileName || null;
|
|
397
397
|
const usedExternalUrl = geminiRun.input.videoFile.usedExternalUrl || false;
|
|
398
398
|
|
|
399
|
-
analysis = geminiRun.output.parsed || { rawResponse: geminiRun.output.raw };
|
|
399
|
+
analysis = normalizeAnalysis(geminiRun.output.parsed || { rawResponse: geminiRun.output.raw });
|
|
400
400
|
analysis._geminiMeta = {
|
|
401
401
|
model: geminiRun.run.model,
|
|
402
402
|
processedAt: geminiRun.run.timestamp,
|
|
@@ -474,7 +474,7 @@ async function phaseProcessVideo(ctx, videoPath, videoIndex) {
|
|
|
474
474
|
const retryRunFilePath = path.join(geminiRunsDir, retryRunFileName);
|
|
475
475
|
fs.writeFileSync(retryRunFilePath, JSON.stringify(retryRun, null, 2), 'utf8');
|
|
476
476
|
|
|
477
|
-
const retryAnalysis = retryRun.output.parsed || { rawResponse: retryRun.output.raw };
|
|
477
|
+
const retryAnalysis = normalizeAnalysis(retryRun.output.parsed || { rawResponse: retryRun.output.raw });
|
|
478
478
|
const retryQuality = assessQuality(retryAnalysis, {
|
|
479
479
|
parseSuccess: retryRun.output.parseSuccess,
|
|
480
480
|
rawLength: (retryRun.output.raw || '').length,
|
|
@@ -492,7 +492,7 @@ async function phaseProcessVideo(ctx, videoPath, videoIndex) {
|
|
|
492
492
|
// Use retry result if better
|
|
493
493
|
if (retryQuality.score > qualityReport.score) {
|
|
494
494
|
retryImproved = true;
|
|
495
|
-
analysis = retryAnalysis;
|
|
495
|
+
analysis = normalizeAnalysis(retryAnalysis);
|
|
496
496
|
analysis._geminiMeta = {
|
|
497
497
|
model: retryRun.run.model,
|
|
498
498
|
processedAt: retryRun.run.timestamp,
|
package/src/pipeline.js
CHANGED
|
@@ -231,7 +231,7 @@ async function run() {
|
|
|
231
231
|
async function runDocOnly(ctx) {
|
|
232
232
|
// Lazy imports for doc-only mode
|
|
233
233
|
const { compileFinalResult } = require('./services/gemini');
|
|
234
|
-
const { validateAnalysis, formatSchemaLine } = require('./utils/schema-validator');
|
|
234
|
+
const { validateAnalysis, formatSchemaLine, normalizeAnalysis } = require('./utils/schema-validator');
|
|
235
235
|
const { renderResultsMarkdown } = require('./renderers/markdown');
|
|
236
236
|
const { renderResultsHtml } = require('./renderers/html');
|
|
237
237
|
const { renderResultsPdf } = require('./renderers/pdf');
|
|
@@ -297,7 +297,7 @@ async function runDocOnly(ctx) {
|
|
|
297
297
|
}
|
|
298
298
|
);
|
|
299
299
|
|
|
300
|
-
compiledAnalysis = compilationResult.compiled;
|
|
300
|
+
compiledAnalysis = normalizeAnalysis(compilationResult.compiled);
|
|
301
301
|
compilationRun = compilationResult.run;
|
|
302
302
|
|
|
303
303
|
if (compilationRun?.tokenUsage) {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"description": "JSON Schema for a single segment's AI analysis output. Uses additionalProperties:true to allow extra fields without failing.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": true,
|
|
8
|
-
"required": ["
|
|
8
|
+
"required": ["summary"],
|
|
9
9
|
"properties": {
|
|
10
10
|
"tickets": {
|
|
11
11
|
"type": "array",
|
|
@@ -29,14 +29,16 @@ const THRESHOLDS = {
|
|
|
29
29
|
|
|
30
30
|
// Required top-level fields in a valid analysis
|
|
31
31
|
const REQUIRED_FIELDS = [
|
|
32
|
-
'tickets',
|
|
33
|
-
'action_items',
|
|
34
|
-
'change_requests',
|
|
35
32
|
'summary',
|
|
36
33
|
];
|
|
37
34
|
|
|
38
35
|
// Optional but valuable fields (boost score when present)
|
|
36
|
+
// tickets, action_items, change_requests are here because a segment may
|
|
37
|
+
// legitimately contain none of these (e.g. a segment that is only chit-chat).
|
|
39
38
|
const VALUED_FIELDS = [
|
|
39
|
+
'tickets',
|
|
40
|
+
'action_items',
|
|
41
|
+
'change_requests',
|
|
40
42
|
'blockers',
|
|
41
43
|
'scope_changes',
|
|
42
44
|
'file_references',
|
|
@@ -70,11 +72,11 @@ function scoreStructure(analysis) {
|
|
|
70
72
|
let bonus = 0;
|
|
71
73
|
for (const field of VALUED_FIELDS) {
|
|
72
74
|
if (analysis[field] !== undefined && analysis[field] !== null) {
|
|
73
|
-
bonus +=
|
|
75
|
+
bonus += 2; // up to 14 bonus points (7 valued fields)
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
78
|
|
|
77
|
-
const baseScore = (present / REQUIRED_FIELDS.length) *
|
|
79
|
+
const baseScore = (present / REQUIRED_FIELDS.length) * 70;
|
|
78
80
|
return { score: Math.min(100, baseScore + bonus), issues };
|
|
79
81
|
}
|
|
80
82
|
|
|
@@ -335,7 +337,7 @@ function buildRetryHints(analysis, issues) {
|
|
|
335
337
|
const hints = [];
|
|
336
338
|
|
|
337
339
|
if (issues.some(i => i.includes('Missing required field'))) {
|
|
338
|
-
hints.push('CRITICAL: Your previous response was missing required
|
|
340
|
+
hints.push('CRITICAL: Your previous response was missing the required "summary" field. You MUST include a "summary" string. Include tickets, action_items, and change_requests arrays if relevant — omit them or use empty arrays [] if none exist in this segment.');
|
|
339
341
|
}
|
|
340
342
|
|
|
341
343
|
if (issues.some(i => i.includes('JSON parse failed'))) {
|
|
@@ -306,9 +306,38 @@ function formatSchemaLine(report) {
|
|
|
306
306
|
return ` ${c.warn(`Schema: ${report.errorCount} error(s) — ${report.errors.slice(0, 2).map(e => e.message).join('; ')}`)}`;
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
+
// ======================== POST-PARSE NORMALIZATION ========================
|
|
310
|
+
|
|
311
|
+
/** Array fields that should default to [] when missing from analysis output. */
|
|
312
|
+
const ARRAY_DEFAULTS = [
|
|
313
|
+
'tickets', 'action_items', 'change_requests',
|
|
314
|
+
'blockers', 'scope_changes', 'file_references',
|
|
315
|
+
];
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Normalize a parsed analysis object by filling in missing array fields
|
|
319
|
+
* with empty arrays. This prevents downstream code from crashing when
|
|
320
|
+
* a segment legitimately has no tickets/action_items/etc.
|
|
321
|
+
*
|
|
322
|
+
* Mutates `data` in-place and returns it for convenience.
|
|
323
|
+
*
|
|
324
|
+
* @param {object} data - Parsed analysis (may have missing fields)
|
|
325
|
+
* @returns {object} The same object with defaults applied
|
|
326
|
+
*/
|
|
327
|
+
function normalizeAnalysis(data) {
|
|
328
|
+
if (!data || typeof data !== 'object') return data;
|
|
329
|
+
for (const field of ARRAY_DEFAULTS) {
|
|
330
|
+
if (data[field] === undefined || data[field] === null) {
|
|
331
|
+
data[field] = [];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return data;
|
|
335
|
+
}
|
|
336
|
+
|
|
309
337
|
module.exports = {
|
|
310
338
|
validateAnalysis,
|
|
311
339
|
buildSchemaRetryHints,
|
|
312
340
|
schemaScore,
|
|
313
341
|
formatSchemaLine,
|
|
342
|
+
normalizeAnalysis,
|
|
314
343
|
};
|