feat(telemetry): Integrate AI usage telemetry into parse-prd

Implements AI usage telemetry capture and propagation for the  command and MCP tool, following the established telemetry pattern.

Key changes:

-   **Core ():**
    -   Modified the  call to include  and .
    -   Updated to receive  from .
    -   Adjusted to return an object .
    -   Added a call to  to show telemetry data in the CLI output when not in MCP mode.

-   **Direct Function ():**
    -   Updated the call to the core  function to pass , , and .
    -   Modified to correctly handle the new return structure from the core function.
    -   Ensures  received from the core function is included in the  field of the successful MCP response.

-   **MCP Tool ():**
    -   No changes required; existing  correctly passes through the  object containing .

-   **CLI Command ():**
    -   The  command's action now relies on the core  function to handle CLI success messages and telemetry display.

This ensures that AI usage for the  functionality is tracked and can be displayed or logged as appropriate for both CLI and MCP interactions.
This commit is contained in:
Eyal Toledano
2025-05-07 14:22:42 -04:00
parent 0288311965
commit f89d2aacc0
4 changed files with 54 additions and 44 deletions

View File

@@ -17,6 +17,7 @@ import {
import { generateObjectService } from '../ai-services-unified.js';
import { getDebugFlag } from '../config-manager.js';
import generateTaskFiles from './generate-task-files.js';
import { displayAiUsageSummary } from '../ui.js';
// Define the Zod schema for a SINGLE task object
const prdSingleTaskSchema = z.object({
@@ -95,6 +96,7 @@ async function parsePRD(prdPath, tasksPath, numTasks, options = {}) {
let existingTasks = [];
let nextId = 1;
let aiServiceResponse = null;
try {
// Handle file existence and overwrite/append logic
@@ -206,8 +208,8 @@ Guidelines:
// Call the unified AI service
report('Calling AI service to generate tasks from PRD...', 'info');
// Call generateObjectService with the CORRECT schema
const generatedData = await generateObjectService({
// Call generateObjectService with the CORRECT schema and additional telemetry params
aiServiceResponse = await generateObjectService({
role: 'main',
session: session,
projectRoot: projectRoot,
@@ -215,7 +217,8 @@ Guidelines:
objectName: 'tasks_data',
systemPrompt: systemPrompt,
prompt: userPrompt,
reportProgress
commandName: 'parse-prd',
outputType: isMCP ? 'mcp' : 'cli'
});
// Create the directory if it doesn't exist
@@ -223,12 +226,12 @@ Guidelines:
if (!fs.existsSync(tasksDir)) {
fs.mkdirSync(tasksDir, { recursive: true });
}
logFn.success('Successfully parsed PRD via AI service.'); // Assumes generateObjectService validated
logFn.success('Successfully parsed PRD via AI service.');
// Validate and Process Tasks
const generatedData = aiServiceResponse?.mainResult?.object;
if (!generatedData || !Array.isArray(generatedData.tasks)) {
// This error *shouldn't* happen if generateObjectService enforced prdResponseSchema
// But keep it as a safeguard
logFn.error(
`Internal Error: generateObjectService returned unexpected data structure: ${JSON.stringify(generatedData)}`
);
@@ -265,36 +268,27 @@ Guidelines:
);
});
const allTasks = useAppend
const finalTasks = useAppend
? [...existingTasks, ...processedNewTasks]
: processedNewTasks;
const outputData = { tasks: finalTasks };
const finalTaskData = { tasks: allTasks }; // Use the combined list
// Write the tasks to the file
writeJSON(tasksPath, finalTaskData);
// Write the final tasks to the file
writeJSON(tasksPath, outputData);
report(
`Successfully wrote ${allTasks.length} total tasks to ${tasksPath} (${processedNewTasks.length} new).`,
`Successfully ${useAppend ? 'appended' : 'generated'} ${processedNewTasks.length} tasks in ${tasksPath}`,
'success'
);
report(`Tasks saved to: ${tasksPath}`, 'info');
// Generate individual task files
if (reportProgress && mcpLog) {
// Enable silent mode when being called from MCP server
enableSilentMode();
await generateTaskFiles(tasksPath, path.dirname(tasksPath));
disableSilentMode();
} else {
await generateTaskFiles(tasksPath, path.dirname(tasksPath));
}
// Generate markdown task files after writing tasks.json
await generateTaskFiles(tasksPath, path.dirname(tasksPath), { mcpLog });
// Only show success boxes for text output (CLI)
// Handle CLI output (e.g., success message)
if (outputFormat === 'text') {
console.log(
boxen(
chalk.green(
`Successfully generated ${processedNewTasks.length} new tasks. Total tasks in ${tasksPath}: ${allTasks.length}`
`Successfully generated ${processedNewTasks.length} new tasks. Total tasks in ${tasksPath}: ${finalTasks.length}`
),
{ padding: 1, borderColor: 'green', borderStyle: 'round' }
)
@@ -314,9 +308,18 @@ Guidelines:
}
)
);
if (aiServiceResponse && aiServiceResponse.telemetryData) {
displayAiUsageSummary(aiServiceResponse.telemetryData, 'cli');
}
}
return { success: true, tasks: processedNewTasks };
// Return telemetry data
return {
success: true,
tasksPath,
telemetryData: aiServiceResponse?.telemetryData
};
} catch (error) {
report(`Error parsing PRD: ${error.message}`, 'error');