@@ -42,7 +42,11 @@ export function createMemoryReadTool(memory: Memory) {
4242// TOOL BUILDER
4343// ============================================================================
4444
45- export function createTools ( memory : Memory , intervals : IntervalsClient | null ) {
45+ export function createTools (
46+ memory : Memory ,
47+ intervals : IntervalsClient | null ,
48+ intervalsAuth : { apiKey : string ; athleteId : string } | null ,
49+ ) {
4650 return {
4751 // ── Cycling logic tools (local, no API) ─────────────────────────────
4852
@@ -207,15 +211,18 @@ export function createTools(memory: Memory, intervals: IntervalsClient | null) {
207211
208212 // ── Intervals.icu tools ─────────────────────────────────────────────
209213
210- ...( intervals ? createIntervalsTools ( intervals ) : { } ) ,
214+ ...( intervals && intervalsAuth ? createIntervalsTools ( intervals , intervalsAuth ) : { } ) ,
211215 } ;
212216}
213217
214218// ============================================================================
215219// INTERVALS.ICU TOOLS
216220// ============================================================================
217221
218- function createIntervalsTools ( client : IntervalsClient ) {
222+ function createIntervalsTools (
223+ client : IntervalsClient ,
224+ auth : { apiKey : string ; athleteId : string } ,
225+ ) {
219226 return {
220227 intervals_fetch_athlete : tool ( {
221228 description :
@@ -303,5 +310,56 @@ function createIntervalsTools(client: IntervalsClient) {
303310 return { created : true , event : result . value } ;
304311 } ,
305312 } ) ,
313+
314+ intervals_list_events : tool ( {
315+ description :
316+ "List scheduled calendar workouts on intervals.icu for a date range. " +
317+ "Use this BEFORE deleting so you can show the athlete the list (id, date, name) " +
318+ "and ask which one to delete. Filters to WORKOUT category only." ,
319+ inputSchema : zodSchema (
320+ z . object ( {
321+ oldest : z . string ( ) . describe ( "Oldest date (YYYY-MM-DD)" ) ,
322+ newest : z . string ( ) . optional ( ) . describe ( "Newest date (YYYY-MM-DD)" ) ,
323+ } ) ,
324+ ) ,
325+ execute : async ( input : { oldest : string ; newest ?: string } ) => {
326+ const result = await client . events . list ( {
327+ oldest : input . oldest ,
328+ newest : input . newest ?? undefined ,
329+ category : [ "WORKOUT" ] ,
330+ } ) ;
331+ if ( ! result . ok ) return { error : result . error . kind } ;
332+ return result . value ;
333+ } ,
334+ } ) ,
335+
336+ intervals_delete_workout : tool ( {
337+ description :
338+ "Delete a scheduled workout from the intervals.icu calendar by event ID. " +
339+ "ALWAYS call intervals_list_events first, show the athlete the list, and " +
340+ "confirm which workout to delete before calling this. Past workouts (before " +
341+ "today) are protected — the server will reject the delete." ,
342+ inputSchema : zodSchema (
343+ z . object ( {
344+ eventId : z . number ( ) . int ( ) . describe ( "Event ID from intervals_list_events" ) ,
345+ } ) ,
346+ ) ,
347+ execute : async ( input : { eventId : number } ) => {
348+ const today = new Date ( ) . toISOString ( ) . split ( "T" ) [ 0 ] ;
349+ const url =
350+ `https://intervals.icu/api/v1/athlete/${ auth . athleteId } ` +
351+ `/events/${ input . eventId } ?notBefore=${ today } ` ;
352+ const basic = Buffer . from ( `API_KEY:${ auth . apiKey } ` ) . toString ( "base64" ) ;
353+ const res = await fetch ( url , {
354+ method : "DELETE" ,
355+ headers : { Authorization : `Basic ${ basic } ` } ,
356+ } ) ;
357+ if ( ! res . ok ) {
358+ const body = await res . text ( ) . catch ( ( ) => "" ) ;
359+ return { error : `http_${ res . status } ` , message : body || res . statusText } ;
360+ }
361+ return { deleted : true } ;
362+ } ,
363+ } ) ,
306364 } ;
307365}
0 commit comments