agents 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{client-storage-yDVwzgfF.d.ts → client-storage-BPjfP_is.d.ts} +2 -2
- package/dist/experimental/forever.d.ts +3 -2
- package/dist/index.d.ts +30 -3
- package/dist/index.js +141 -82
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.d.ts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/package.json +1 -1
|
@@ -554,7 +554,7 @@ declare class MCPClientConnection {
|
|
|
554
554
|
*/
|
|
555
555
|
getTransport(
|
|
556
556
|
transportType: BaseTransportType
|
|
557
|
-
):
|
|
557
|
+
): StreamableHTTPClientTransport | SSEClientTransport | RPCClientTransport;
|
|
558
558
|
private tryConnect;
|
|
559
559
|
private _capabilityErrorHandler;
|
|
560
560
|
}
|
|
@@ -601,4 +601,4 @@ export {
|
|
|
601
601
|
MaybePromise as x,
|
|
602
602
|
StreamableHTTPEdgeClientTransport as y
|
|
603
603
|
};
|
|
604
|
-
//# sourceMappingURL=client-storage-
|
|
604
|
+
//# sourceMappingURL=client-storage-BPjfP_is.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RetryOptions } from "../retries.js";
|
|
2
|
-
import "../client-storage-
|
|
2
|
+
import "../client-storage-BPjfP_is.js";
|
|
3
3
|
import { Agent, Schedule } from "../index.js";
|
|
4
4
|
|
|
5
5
|
//#region src/experimental/forever.d.ts
|
|
@@ -92,12 +92,13 @@ declare function withFibers<TBase extends AgentLike>(Base: TBase, options?: {
|
|
|
92
92
|
_checkInterruptedFibers(): Promise<void>; /** @internal */
|
|
93
93
|
_cleanupOrphanedHeartbeats(): void; /** @internal */
|
|
94
94
|
_maybeCleanupFibers(): void;
|
|
95
|
-
readonly alarm: () => Promise<void>;
|
|
96
95
|
sql: <T = Record<string, string | number | boolean | null>>(strings: TemplateStringsArray, ...values: (string | number | boolean | null)[]) => T[];
|
|
97
96
|
scheduleEvery: <T = string>(intervalSeconds: number, callback: keyof Agent<Cloudflare.Env, unknown, Record<string, unknown>>, payload?: T | undefined, options?: {
|
|
98
97
|
retry?: RetryOptions;
|
|
98
|
+
_idempotent?: boolean;
|
|
99
99
|
}) => Promise<Schedule<T>>;
|
|
100
100
|
cancelSchedule: (id: string) => Promise<boolean>;
|
|
101
|
+
alarm: () => Promise<void>;
|
|
101
102
|
keepAlive: () => Promise<() => void>;
|
|
102
103
|
keepAliveWhile: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
103
104
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { RetryOptions } from "./retries.js";
|
|
|
7
7
|
import {
|
|
8
8
|
r as MCPConnectionState,
|
|
9
9
|
w as TransportType
|
|
10
|
-
} from "./client-storage-
|
|
10
|
+
} from "./client-storage-BPjfP_is.js";
|
|
11
11
|
import {
|
|
12
12
|
AgentMcpOAuthProvider,
|
|
13
13
|
AgentsOAuthProvider,
|
|
@@ -596,7 +596,23 @@ declare class Agent<
|
|
|
596
596
|
}
|
|
597
597
|
): Promise<Schedule<T>>;
|
|
598
598
|
/**
|
|
599
|
-
* Schedule a task to run repeatedly at a fixed interval
|
|
599
|
+
* Schedule a task to run repeatedly at a fixed interval.
|
|
600
|
+
*
|
|
601
|
+
* This method is **idempotent** — calling it multiple times with the same
|
|
602
|
+
* `callback`, `intervalSeconds`, and `payload` returns the existing schedule
|
|
603
|
+
* instead of creating a duplicate. A different interval or payload is
|
|
604
|
+
* treated as a distinct schedule and creates a new row.
|
|
605
|
+
*
|
|
606
|
+
* This makes it safe to call in `onStart()`, which runs on every Durable
|
|
607
|
+
* Object wake:
|
|
608
|
+
*
|
|
609
|
+
* ```ts
|
|
610
|
+
* async onStart() {
|
|
611
|
+
* // Only one schedule is created, no matter how many times the DO wakes
|
|
612
|
+
* await this.scheduleEvery(30, "tick");
|
|
613
|
+
* }
|
|
614
|
+
* ```
|
|
615
|
+
*
|
|
600
616
|
* @template T Type of the payload data
|
|
601
617
|
* @param intervalSeconds Number of seconds between executions
|
|
602
618
|
* @param callback Name of the method to call
|
|
@@ -611,6 +627,7 @@ declare class Agent<
|
|
|
611
627
|
payload?: T,
|
|
612
628
|
options?: {
|
|
613
629
|
retry?: RetryOptions;
|
|
630
|
+
_idempotent?: boolean;
|
|
614
631
|
}
|
|
615
632
|
): Promise<Schedule<T>>;
|
|
616
633
|
/**
|
|
@@ -688,15 +705,25 @@ declare class Agent<
|
|
|
688
705
|
*/
|
|
689
706
|
_cf_keepAliveHeartbeat(): Promise<void>;
|
|
690
707
|
private _scheduleNextAlarm;
|
|
708
|
+
/**
|
|
709
|
+
* Override PartyServer's onAlarm hook as a no-op.
|
|
710
|
+
* Agent handles alarm logic directly in the alarm() method override,
|
|
711
|
+
* but super.alarm() calls onAlarm() after #ensureInitialized(),
|
|
712
|
+
* so we suppress the default "Implement onAlarm" warning.
|
|
713
|
+
*/
|
|
714
|
+
onAlarm(): void;
|
|
691
715
|
/**
|
|
692
716
|
* Method called when an alarm fires.
|
|
693
717
|
* Executes any scheduled tasks that are due.
|
|
694
718
|
*
|
|
719
|
+
* Calls super.alarm() first to ensure PartyServer's #ensureInitialized()
|
|
720
|
+
* runs, which hydrates this.name from storage and calls onStart() if needed.
|
|
721
|
+
*
|
|
695
722
|
* @remarks
|
|
696
723
|
* To schedule a task, please use the `this.schedule` method instead.
|
|
697
724
|
* See {@link https://developers.cloudflare.com/agents/api-reference/schedule-tasks/}
|
|
698
725
|
*/
|
|
699
|
-
|
|
726
|
+
alarm(): Promise<void>;
|
|
700
727
|
/**
|
|
701
728
|
* Destroy the Agent, removing all state and scheduled tasks
|
|
702
729
|
*/
|
package/dist/index.js
CHANGED
|
@@ -293,85 +293,6 @@ var Agent = class Agent extends Server {
|
|
|
293
293
|
this.initialState = DEFAULT_STATE;
|
|
294
294
|
this.observability = genericObservability;
|
|
295
295
|
this._flushingQueue = false;
|
|
296
|
-
this.alarm = async () => {
|
|
297
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
298
|
-
const result = this.sql`
|
|
299
|
-
SELECT * FROM cf_agents_schedules WHERE time <= ${now}
|
|
300
|
-
`;
|
|
301
|
-
if (result && Array.isArray(result)) for (const row of result) {
|
|
302
|
-
const callback = this[row.callback];
|
|
303
|
-
if (!callback) {
|
|
304
|
-
console.error(`callback ${row.callback} not found`);
|
|
305
|
-
continue;
|
|
306
|
-
}
|
|
307
|
-
if (row.type === "interval" && row.running === 1) {
|
|
308
|
-
const executionStartedAt = row.execution_started_at ?? 0;
|
|
309
|
-
const hungTimeoutSeconds = this._resolvedOptions.hungScheduleTimeoutSeconds;
|
|
310
|
-
const elapsedSeconds = now - executionStartedAt;
|
|
311
|
-
if (elapsedSeconds < hungTimeoutSeconds) {
|
|
312
|
-
console.warn(`Skipping interval schedule ${row.id}: previous execution still running`);
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
console.warn(`Forcing reset of hung interval schedule ${row.id} (started ${elapsedSeconds}s ago)`);
|
|
316
|
-
}
|
|
317
|
-
if (row.type === "interval") this.sql`UPDATE cf_agents_schedules SET running = 1, execution_started_at = ${now} WHERE id = ${row.id}`;
|
|
318
|
-
await __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
319
|
-
agent: this,
|
|
320
|
-
connection: void 0,
|
|
321
|
-
request: void 0,
|
|
322
|
-
email: void 0
|
|
323
|
-
}, async () => {
|
|
324
|
-
const { maxAttempts, baseDelayMs, maxDelayMs } = resolveRetryConfig(parseRetryOptions(row), this._resolvedOptions.retry);
|
|
325
|
-
const parsedPayload = JSON.parse(row.payload);
|
|
326
|
-
try {
|
|
327
|
-
this._emit("schedule:execute", {
|
|
328
|
-
callback: row.callback,
|
|
329
|
-
id: row.id
|
|
330
|
-
});
|
|
331
|
-
await tryN(maxAttempts, async (attempt) => {
|
|
332
|
-
if (attempt > 1) this._emit("schedule:retry", {
|
|
333
|
-
callback: row.callback,
|
|
334
|
-
id: row.id,
|
|
335
|
-
attempt,
|
|
336
|
-
maxAttempts
|
|
337
|
-
});
|
|
338
|
-
await callback.bind(this)(parsedPayload, row);
|
|
339
|
-
}, {
|
|
340
|
-
baseDelayMs,
|
|
341
|
-
maxDelayMs
|
|
342
|
-
});
|
|
343
|
-
} catch (e) {
|
|
344
|
-
console.error(`error executing callback "${row.callback}" after ${maxAttempts} attempts`, e);
|
|
345
|
-
this._emit("schedule:error", {
|
|
346
|
-
callback: row.callback,
|
|
347
|
-
id: row.id,
|
|
348
|
-
error: e instanceof Error ? e.message : String(e),
|
|
349
|
-
attempts: maxAttempts
|
|
350
|
-
});
|
|
351
|
-
try {
|
|
352
|
-
await this.onError(e);
|
|
353
|
-
} catch {}
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
if (this._destroyed) return;
|
|
357
|
-
if (row.type === "cron") {
|
|
358
|
-
const nextExecutionTime = getNextCronTime(row.cron);
|
|
359
|
-
const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
|
|
360
|
-
this.sql`
|
|
361
|
-
UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}
|
|
362
|
-
`;
|
|
363
|
-
} else if (row.type === "interval") {
|
|
364
|
-
const nextTimestamp = Math.floor(Date.now() / 1e3) + (row.intervalSeconds ?? 0);
|
|
365
|
-
this.sql`
|
|
366
|
-
UPDATE cf_agents_schedules SET running = 0, time = ${nextTimestamp} WHERE id = ${row.id}
|
|
367
|
-
`;
|
|
368
|
-
} else this.sql`
|
|
369
|
-
DELETE FROM cf_agents_schedules WHERE id = ${row.id}
|
|
370
|
-
`;
|
|
371
|
-
}
|
|
372
|
-
if (this._destroyed) return;
|
|
373
|
-
await this._scheduleNextAlarm();
|
|
374
|
-
};
|
|
375
296
|
if (!wrappedClasses.has(this.constructor)) {
|
|
376
297
|
this._autoWrapCustomMethods();
|
|
377
298
|
wrappedClasses.add(this.constructor);
|
|
@@ -1300,7 +1221,23 @@ var Agent = class Agent extends Server {
|
|
|
1300
1221
|
throw new Error(`Invalid schedule type: ${JSON.stringify(when)}(${typeof when}) trying to schedule ${callback}`);
|
|
1301
1222
|
}
|
|
1302
1223
|
/**
|
|
1303
|
-
* Schedule a task to run repeatedly at a fixed interval
|
|
1224
|
+
* Schedule a task to run repeatedly at a fixed interval.
|
|
1225
|
+
*
|
|
1226
|
+
* This method is **idempotent** — calling it multiple times with the same
|
|
1227
|
+
* `callback`, `intervalSeconds`, and `payload` returns the existing schedule
|
|
1228
|
+
* instead of creating a duplicate. A different interval or payload is
|
|
1229
|
+
* treated as a distinct schedule and creates a new row.
|
|
1230
|
+
*
|
|
1231
|
+
* This makes it safe to call in `onStart()`, which runs on every Durable
|
|
1232
|
+
* Object wake:
|
|
1233
|
+
*
|
|
1234
|
+
* ```ts
|
|
1235
|
+
* async onStart() {
|
|
1236
|
+
* // Only one schedule is created, no matter how many times the DO wakes
|
|
1237
|
+
* await this.scheduleEvery(30, "tick");
|
|
1238
|
+
* }
|
|
1239
|
+
* ```
|
|
1240
|
+
*
|
|
1304
1241
|
* @template T Type of the payload data
|
|
1305
1242
|
* @param intervalSeconds Number of seconds between executions
|
|
1306
1243
|
* @param callback Name of the method to call
|
|
@@ -1316,13 +1253,37 @@ var Agent = class Agent extends Server {
|
|
|
1316
1253
|
if (typeof callback !== "string") throw new Error("Callback must be a string");
|
|
1317
1254
|
if (typeof this[callback] !== "function") throw new Error(`this.${callback} is not a function`);
|
|
1318
1255
|
if (options?.retry) validateRetryOptions(options.retry, this._resolvedOptions.retry);
|
|
1256
|
+
const idempotent = options?._idempotent !== false;
|
|
1257
|
+
const payloadJson = JSON.stringify(payload);
|
|
1258
|
+
if (idempotent) {
|
|
1259
|
+
const existing = this.sql`
|
|
1260
|
+
SELECT * FROM cf_agents_schedules
|
|
1261
|
+
WHERE type = 'interval'
|
|
1262
|
+
AND callback = ${callback}
|
|
1263
|
+
AND intervalSeconds = ${intervalSeconds}
|
|
1264
|
+
AND payload IS ${payloadJson}
|
|
1265
|
+
LIMIT 1
|
|
1266
|
+
`;
|
|
1267
|
+
if (existing.length > 0) {
|
|
1268
|
+
const row = existing[0];
|
|
1269
|
+
return {
|
|
1270
|
+
callback: row.callback,
|
|
1271
|
+
id: row.id,
|
|
1272
|
+
intervalSeconds: row.intervalSeconds,
|
|
1273
|
+
payload: JSON.parse(row.payload),
|
|
1274
|
+
retry: parseRetryOptions(row),
|
|
1275
|
+
time: row.time,
|
|
1276
|
+
type: "interval"
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1319
1280
|
const id = nanoid(9);
|
|
1320
1281
|
const time = new Date(Date.now() + intervalSeconds * 1e3);
|
|
1321
1282
|
const timestamp = Math.floor(time.getTime() / 1e3);
|
|
1322
1283
|
const retryJson = options?.retry ? JSON.stringify(options.retry) : null;
|
|
1323
1284
|
this.sql`
|
|
1324
1285
|
INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, intervalSeconds, time, running, retry_options)
|
|
1325
|
-
VALUES (${id}, ${callback}, ${
|
|
1286
|
+
VALUES (${id}, ${callback}, ${payloadJson}, 'interval', ${intervalSeconds}, ${timestamp}, 0, ${retryJson})
|
|
1326
1287
|
`;
|
|
1327
1288
|
await this._scheduleNextAlarm();
|
|
1328
1289
|
const schedule = {
|
|
@@ -1425,7 +1386,7 @@ var Agent = class Agent extends Server {
|
|
|
1425
1386
|
*/
|
|
1426
1387
|
async keepAlive() {
|
|
1427
1388
|
const heartbeatSeconds = Math.ceil(KEEP_ALIVE_INTERVAL_MS / 1e3);
|
|
1428
|
-
const schedule = await this.scheduleEvery(heartbeatSeconds, "_cf_keepAliveHeartbeat");
|
|
1389
|
+
const schedule = await this.scheduleEvery(heartbeatSeconds, "_cf_keepAliveHeartbeat", void 0, { _idempotent: false });
|
|
1429
1390
|
let disposed = false;
|
|
1430
1391
|
return () => {
|
|
1431
1392
|
if (disposed) return;
|
|
@@ -1480,6 +1441,104 @@ var Agent = class Agent extends Server {
|
|
|
1480
1441
|
}
|
|
1481
1442
|
}
|
|
1482
1443
|
/**
|
|
1444
|
+
* Override PartyServer's onAlarm hook as a no-op.
|
|
1445
|
+
* Agent handles alarm logic directly in the alarm() method override,
|
|
1446
|
+
* but super.alarm() calls onAlarm() after #ensureInitialized(),
|
|
1447
|
+
* so we suppress the default "Implement onAlarm" warning.
|
|
1448
|
+
*/
|
|
1449
|
+
onAlarm() {}
|
|
1450
|
+
/**
|
|
1451
|
+
* Method called when an alarm fires.
|
|
1452
|
+
* Executes any scheduled tasks that are due.
|
|
1453
|
+
*
|
|
1454
|
+
* Calls super.alarm() first to ensure PartyServer's #ensureInitialized()
|
|
1455
|
+
* runs, which hydrates this.name from storage and calls onStart() if needed.
|
|
1456
|
+
*
|
|
1457
|
+
* @remarks
|
|
1458
|
+
* To schedule a task, please use the `this.schedule` method instead.
|
|
1459
|
+
* See {@link https://developers.cloudflare.com/agents/api-reference/schedule-tasks/}
|
|
1460
|
+
*/
|
|
1461
|
+
async alarm() {
|
|
1462
|
+
await super.alarm();
|
|
1463
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1464
|
+
const result = this.sql`
|
|
1465
|
+
SELECT * FROM cf_agents_schedules WHERE time <= ${now}
|
|
1466
|
+
`;
|
|
1467
|
+
if (result && Array.isArray(result)) for (const row of result) {
|
|
1468
|
+
const callback = this[row.callback];
|
|
1469
|
+
if (!callback) {
|
|
1470
|
+
console.error(`callback ${row.callback} not found`);
|
|
1471
|
+
continue;
|
|
1472
|
+
}
|
|
1473
|
+
if (row.type === "interval" && row.running === 1) {
|
|
1474
|
+
const executionStartedAt = row.execution_started_at ?? 0;
|
|
1475
|
+
const hungTimeoutSeconds = this._resolvedOptions.hungScheduleTimeoutSeconds;
|
|
1476
|
+
const elapsedSeconds = now - executionStartedAt;
|
|
1477
|
+
if (elapsedSeconds < hungTimeoutSeconds) {
|
|
1478
|
+
console.warn(`Skipping interval schedule ${row.id}: previous execution still running`);
|
|
1479
|
+
continue;
|
|
1480
|
+
}
|
|
1481
|
+
console.warn(`Forcing reset of hung interval schedule ${row.id} (started ${elapsedSeconds}s ago)`);
|
|
1482
|
+
}
|
|
1483
|
+
if (row.type === "interval") this.sql`UPDATE cf_agents_schedules SET running = 1, execution_started_at = ${now} WHERE id = ${row.id}`;
|
|
1484
|
+
await __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
1485
|
+
agent: this,
|
|
1486
|
+
connection: void 0,
|
|
1487
|
+
request: void 0,
|
|
1488
|
+
email: void 0
|
|
1489
|
+
}, async () => {
|
|
1490
|
+
const { maxAttempts, baseDelayMs, maxDelayMs } = resolveRetryConfig(parseRetryOptions(row), this._resolvedOptions.retry);
|
|
1491
|
+
const parsedPayload = JSON.parse(row.payload);
|
|
1492
|
+
try {
|
|
1493
|
+
this._emit("schedule:execute", {
|
|
1494
|
+
callback: row.callback,
|
|
1495
|
+
id: row.id
|
|
1496
|
+
});
|
|
1497
|
+
await tryN(maxAttempts, async (attempt) => {
|
|
1498
|
+
if (attempt > 1) this._emit("schedule:retry", {
|
|
1499
|
+
callback: row.callback,
|
|
1500
|
+
id: row.id,
|
|
1501
|
+
attempt,
|
|
1502
|
+
maxAttempts
|
|
1503
|
+
});
|
|
1504
|
+
await callback.bind(this)(parsedPayload, row);
|
|
1505
|
+
}, {
|
|
1506
|
+
baseDelayMs,
|
|
1507
|
+
maxDelayMs
|
|
1508
|
+
});
|
|
1509
|
+
} catch (e) {
|
|
1510
|
+
console.error(`error executing callback "${row.callback}" after ${maxAttempts} attempts`, e);
|
|
1511
|
+
this._emit("schedule:error", {
|
|
1512
|
+
callback: row.callback,
|
|
1513
|
+
id: row.id,
|
|
1514
|
+
error: e instanceof Error ? e.message : String(e),
|
|
1515
|
+
attempts: maxAttempts
|
|
1516
|
+
});
|
|
1517
|
+
try {
|
|
1518
|
+
await this.onError(e);
|
|
1519
|
+
} catch {}
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1522
|
+
if (this._destroyed) return;
|
|
1523
|
+
if (row.type === "cron") {
|
|
1524
|
+
const nextExecutionTime = getNextCronTime(row.cron);
|
|
1525
|
+
const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
|
|
1526
|
+
this.sql`
|
|
1527
|
+
UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}
|
|
1528
|
+
`;
|
|
1529
|
+
} else if (row.type === "interval") {
|
|
1530
|
+
const nextTimestamp = Math.floor(Date.now() / 1e3) + (row.intervalSeconds ?? 0);
|
|
1531
|
+
this.sql`
|
|
1532
|
+
UPDATE cf_agents_schedules SET running = 0, time = ${nextTimestamp} WHERE id = ${row.id}
|
|
1533
|
+
`;
|
|
1534
|
+
} else this.sql`
|
|
1535
|
+
DELETE FROM cf_agents_schedules WHERE id = ${row.id}
|
|
1536
|
+
`;
|
|
1537
|
+
}
|
|
1538
|
+
if (this._destroyed) return;
|
|
1539
|
+
await this._scheduleNextAlarm();
|
|
1540
|
+
}
|
|
1541
|
+
/**
|
|
1483
1542
|
* Destroy the Agent, removing all state and scheduled tasks
|
|
1484
1543
|
*/
|
|
1485
1544
|
async destroy() {
|