Skip to content

Commit a9910d7

Browse files
committed
feat: Enhance tool identifiers and improve logging for data processing tools
- Updated tool IDs to follow a more consistent naming convention (e.g., 'read:data-file' to 'read:file'). - Improved progress logging messages to provide clearer feedback during file operations. - Added tracing policies for better observability in tools like pdfToMarkdown and editorTool. - Refactored the weatherTool to include unit in the output schema and enhanced error handling. - Introduced new tools for PDF data conversion and document chunking with improved metadata extraction. - Updated index file to export new tools and types for better accessibility.
1 parent 960655d commit a9910d7

8 files changed

Lines changed: 188 additions & 98 deletions

.agent/rules/conventions.md

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,97 @@
11
---
22
trigger: model_decision
33
description: Mastra Conventions
4+
name: conventions
5+
title: Mastra Code Conventions
6+
tags:
7+
- conventions
8+
- coding-standards
9+
- best-practices
410
---
5-
6-
# Code Conventions
11+
Code Conventions
712

813
## Tool Implementation Pattern
914

1015
All tools follow this structure:
1116

1217
```typescript
18+
import type { InferUITool} from "@mastra/core/tools";
1319
import { createTool } from "@mastra/core/tools";
1420
import { z } from "zod";
15-
import { AISpanType } from "@mastra/core/ai-tracing";
21+
import { AISpanType, InternalSpans } from "@mastra/core/ai-tracing";
1622
import type { RuntimeContext } from "@mastra/core/runtime-context";
1723
import { log } from "../config/logger";
24+
import type { RuntimeContext } from '@mastra/core/runtime-context'
25+
import type { TracingContext } from '@mastra/core/ai-tracing';
26+
27+
// Define the Zod schema for the runtime context
28+
const weatherToolContextSchema = z.object({
29+
temperatureUnit: z.enum(['celsius', 'fahrenheit']).default('celsius'),
30+
})
31+
32+
// Infer the TypeScript type from the Zod schema
33+
export type WeatherToolContext = z.infer<typeof weatherToolContextSchema>
34+
35+
export const weatherTool = createTool({
36+
id: 'get-weather',
37+
description: 'Get current weather for a location',
38+
inputSchema: z.object({
39+
location: z.string().describe('City name'),
40+
}),
41+
outputSchema: z.object({
42+
temperature: z.number(),
43+
feelsLike: z.number(),
44+
humidity: z.number(),
45+
windSpeed: z.number(),
46+
windGust: z.number(),
47+
conditions: z.string(),
48+
location: z.string(),
49+
unit: z.string(), // Add unit to output schema
50+
}),
51+
execute: async ({ context, writer, runtimeContext, tracingContext }) => {
52+
await writer?.custom({ type: 'data-tool-progress', data: { message: `🚀 Starting weather lookup for ${context.location}` } });
53+
54+
const { temperatureUnit } = weatherToolContextSchema.parse(
55+
runtimeContext.get('weatherToolContext')
56+
)
57+
58+
log.info(
59+
`Fetching weather for location: ${context.location} in ${temperatureUnit}`
60+
)
61+
62+
const weatherSpan = tracingContext?.currentSpan?.createChildSpan({
63+
type: AISpanType.TOOL_CALL,
64+
name: 'weather-tool',
65+
input: { location: context.location, temperatureUnit },
66+
tracingPolicy: { internal: InternalSpans.ALL },
67+
runtimeContext: runtimeContext as RuntimeContext<WeatherToolContext>,
68+
})
1869

19-
export const myTool = createTool({
20-
id: "my-tool",
21-
description: "Clear description of what the tool does",
22-
inputSchema: z.object({
23-
param: z.string().describe("Parameter description")
24-
}),
25-
outputSchema: z.object({
26-
data: z.any().describe("Result data"),
27-
error: z.string().optional()
28-
}),
29-
execute: async ({ context, tracingContext, runtimeContext }) => {
30-
const startTime = Date.now();
31-
32-
// Create root tracing span
33-
const rootSpan = tracingContext?.currentSpan?.createChildSpan({
34-
type: AISpanType.TOOL_CALL,
35-
name: 'my-tool',
36-
input: context,
37-
});
38-
39-
try {
40-
// Tool logic here
41-
log.info('my-tool executed', { context });
42-
43-
rootSpan?.end({ output: result });
44-
return result;
45-
} catch (error) {
46-
log.error('my-tool error', { error, context });
47-
rootSpan?.error({ error });
48-
return { data: null, error: errorMessage };
49-
}
50-
}
51-
});
70+
try {
71+
await writer?.custom({ type: 'data-tool-progress', data: { message: '📍 Geocoding location...' } });
72+
const result = await getWeather(context.location, temperatureUnit)
73+
await writer?.custom({ type: 'data-tool-progress', data: { message: '🌤️ Processing weather data...' } });
74+
weatherSpan?.end({ output: result })
75+
log.info(`Weather fetched successfully for ${context.location}`)
76+
const finalResult = {
77+
...result,
78+
unit: temperatureUnit === 'celsius' ? '°C' : '°F',
79+
};
80+
await writer?.custom({ type: 'data-tool-progress', data: { message: `✅ Weather ready: ${finalResult.temperature}${finalResult.unit} in ${finalResult.location}` } });
81+
return finalResult;
82+
} catch (error) {
83+
const errorMessage =
84+
error instanceof Error ? error.message : String(error)
85+
await writer?.custom({ type: 'data-tool-progress', data: { message: `❌ Weather error: ${errorMessage}` } });
86+
weatherSpan?.end({ metadata: { error: errorMessage } })
87+
log.error(
88+
`Failed to fetch weather for ${context.location}: ${errorMessage}`
89+
)
90+
throw error
91+
}
92+
},
93+
})
94+
export type WeatherUITool = InferUITool<typeof weatherTool>;
5295
```
5396

5497
## Key Patterns

0 commit comments

Comments
 (0)