diff --git a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts index 12c595cf3..885939375 100644 --- a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts +++ b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts @@ -4,9 +4,9 @@ import { wrapTraced } from 'braintrust'; import z from 'zod'; import { Sonnet4 } from '../../llm'; import { createExecuteSqlTool, createSequentialThinkingTool } from '../../tools'; -import { createMessageUserClarifyingQuestionTool } from '../../tools/communication-tools/message-user-clarifying-question/message-user-clarifying-question'; -import { createRespondWithoutAssetCreationTool } from '../../tools/communication-tools/respond-without-asset-creation/respond-without-asset-creation-tool'; -import { createSubmitThoughtsTool } from '../../tools/communication-tools/submit-thoughts-tool/submit-thoughts-tool'; +import { createMessageUserClarifyingQuestionTool, MESSAGE_USER_CLARIFYING_QUESTION_TOOL_NAME } from '../../tools/communication-tools/message-user-clarifying-question/message-user-clarifying-question'; +import { createRespondWithoutAssetCreationTool, RESPOND_WITHOUT_ASSET_CREATION_TOOL_NAME } from '../../tools/communication-tools/respond-without-asset-creation/respond-without-asset-creation-tool'; +import { createSubmitThoughtsTool, SUBMIT_THOUGHTS_TOOL_NAME } from '../../tools/communication-tools/submit-thoughts-tool/submit-thoughts-tool'; import { healToolWithLlm } from '../../utils'; import { type AnalysisMode, @@ -23,9 +23,9 @@ const DEFAULT_CACHE_OPTIONS = { const STOP_CONDITIONS = [ stepCountIs(25), - hasToolCall('submitThoughts'), - hasToolCall('respondWithoutAssetCreation'), - hasToolCall('messageUserClarifyingQuestion'), + hasToolCall(SUBMIT_THOUGHTS_TOOL_NAME), + hasToolCall(RESPOND_WITHOUT_ASSET_CREATION_TOOL_NAME), + hasToolCall(MESSAGE_USER_CLARIFYING_QUESTION_TOOL_NAME), ]; export const ThinkAndPrepAgentOptionsSchema = z.object({ diff --git a/packages/ai/src/tools/communication-tools/done-tool/helpers/done-tool-file-selection.ts b/packages/ai/src/tools/communication-tools/done-tool/helpers/done-tool-file-selection.ts index 525e2b401..a26f9d477 100644 --- a/packages/ai/src/tools/communication-tools/done-tool/helpers/done-tool-file-selection.ts +++ b/packages/ai/src/tools/communication-tools/done-tool/helpers/done-tool-file-selection.ts @@ -91,11 +91,11 @@ function processToolOutput(output: unknown, files: ExtractedFile[]): void { } } - // Check if this is a reports tool output - if (isReportsToolOutput(output)) { + // Check if this is a create reports tool output + if (isCreateReportsToolOutput(output)) { const operation = detectOperation(output.message); - // Extract successfully created/modified report files + // Extract successfully created report files if (output.files && Array.isArray(output.files)) { for (const file of output.files) { files.push({ @@ -108,19 +108,20 @@ function processToolOutput(output: unknown, files: ExtractedFile[]): void { }); } } + } + + // Check if this is a modify reports tool output + if (isModifyReportsToolOutput(output)) { // For modify reports tool, extract from the file object - if ('file' in output && output.file && typeof output.file === 'object') { - const file = output.file as Record; - if (file.id && file.name && file.version_number) { - files.push({ - id: file.id as string, - fileType: 'report', - fileName: file.name as string, - status: 'completed', - operation: 'modified', - versionNumber: file.version_number as number, - }); - } + if (output.file && typeof output.file === 'object') { + files.push({ + id: output.file.id, + fileType: 'report', + fileName: output.file.name, + status: 'completed', + operation: 'modified', + versionNumber: output.file.version_number, + }); } } } @@ -168,30 +169,43 @@ function isDashboardsToolOutput( } /** - * Type guard to check if output is from create/modify reports tool + * Type guard to check if output is from create reports tool */ -function isReportsToolOutput(output: unknown): output is CreateReportsOutput | ModifyReportsOutput { +function isCreateReportsToolOutput(output: unknown): output is CreateReportsOutput { if (!output || typeof output !== 'object') return false; const obj = output as Record; // Check for create reports output structure - if ('files' in obj && 'message' in obj && Array.isArray(obj.files)) { - // Check if files have report-specific properties + if ('files' in obj && 'message' in obj && 'failed_files' in obj) { + if (!Array.isArray(obj.files)) return false; + + // Check if files have report-specific properties (id, name, version_number) return obj.files.every((file: unknown) => { if (!file || typeof file !== 'object') return false; const fileObj = file as Record; - // Reports don't have file_type in the output, just id, name, version_number return 'id' in fileObj && 'name' in fileObj && 'version_number' in fileObj; }); } - // Check for modify reports output structure (has a single 'file' property) + return false; +} + +/** + * Type guard to check if output is from modify reports tool + */ +function isModifyReportsToolOutput(output: unknown): output is ModifyReportsOutput { + if (!output || typeof output !== 'object') return false; + + const obj = output as Record; + + // Check for modify reports output structure (has success, message, and file properties) if ('success' in obj && 'message' in obj && 'file' in obj) { const file = obj.file; if (file && typeof file === 'object') { const fileObj = file as Record; - return 'id' in fileObj && 'name' in fileObj && 'version_number' in fileObj; + // Check for required file properties + return 'id' in fileObj && 'name' in fileObj && 'version_number' in fileObj && 'content' in fileObj && 'updated_at' in fileObj; } } diff --git a/packages/ai/src/tools/communication-tools/respond-without-asset-creation/respond-without-asset-creation-tool.ts b/packages/ai/src/tools/communication-tools/respond-without-asset-creation/respond-without-asset-creation-tool.ts index cf009b833..1ae628d87 100644 --- a/packages/ai/src/tools/communication-tools/respond-without-asset-creation/respond-without-asset-creation-tool.ts +++ b/packages/ai/src/tools/communication-tools/respond-without-asset-creation/respond-without-asset-creation-tool.ts @@ -5,6 +5,8 @@ import { createRespondWithoutAssetCreationExecute } from './respond-without-asse import { createRespondWithoutAssetCreationFinish } from './respond-without-asset-creation-finish'; import { createRespondWithoutAssetCreationStart } from './respond-without-asset-creation-start'; +export const RESPOND_WITHOUT_ASSET_CREATION_TOOL_NAME = 'respondWithoutAssetCreation'; + export const RespondWithoutAssetCreationInputSchema = z.object({ final_response: z .string() diff --git a/packages/ai/src/tools/communication-tools/submit-thoughts-tool/submit-thoughts-tool.ts b/packages/ai/src/tools/communication-tools/submit-thoughts-tool/submit-thoughts-tool.ts index 4921dab37..4103aa2c9 100644 --- a/packages/ai/src/tools/communication-tools/submit-thoughts-tool/submit-thoughts-tool.ts +++ b/packages/ai/src/tools/communication-tools/submit-thoughts-tool/submit-thoughts-tool.ts @@ -2,6 +2,8 @@ import { tool } from 'ai'; import { wrapTraced } from 'braintrust'; import { z } from 'zod'; +export const SUBMIT_THOUGHTS_TOOL_NAME = 'submitThoughts'; + // Minimal schemas: no input/output for a signal-only tool const SubmitThoughtsInputSchema = z.object({}); const SubmitThoughtsOutputSchema = z.object({});