more type safety

This commit is contained in:
dal 2025-08-13 10:49:35 -06:00
parent 8299e47e4e
commit 3e1181c121
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
4 changed files with 46 additions and 28 deletions

View File

@ -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({

View File

@ -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,21 +108,22 @@ 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<string, unknown>;
if (file.id && file.name && file.version_number) {
if (output.file && typeof output.file === 'object') {
files.push({
id: file.id as string,
id: output.file.id,
fileType: 'report',
fileName: file.name as string,
fileName: output.file.name,
status: 'completed',
operation: 'modified',
versionNumber: file.version_number as number,
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<string, unknown>;
// 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<string, unknown>;
// 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<string, unknown>;
// 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<string, unknown>;
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;
}
}

View File

@ -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()

View File

@ -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({});