agents 0.9.0 → 0.10.0

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.
Files changed (50) hide show
  1. package/dist/chat/index.d.ts +151 -2
  2. package/dist/chat/index.js +210 -11
  3. package/dist/chat/index.js.map +1 -1
  4. package/dist/{client-BwgM3cRz.js → client-QBjFV5de.js} +161 -49
  5. package/dist/client-QBjFV5de.js.map +1 -0
  6. package/dist/client.d.ts +2 -2
  7. package/dist/{compaction-helpers-BFTBIzpK.js → compaction-helpers-BPE1_ziA.js} +1 -1
  8. package/dist/{compaction-helpers-BFTBIzpK.js.map → compaction-helpers-BPE1_ziA.js.map} +1 -1
  9. package/dist/{compaction-helpers-DkJreaDR.d.ts → compaction-helpers-CHNQeyRm.d.ts} +1 -1
  10. package/dist/{do-oauth-client-provider-C2jurFjW.d.ts → do-oauth-client-provider-31gqR33H.d.ts} +1 -1
  11. package/dist/{email-DwPlM0bQ.d.ts → email-Cql45SKP.d.ts} +1 -1
  12. package/dist/email.d.ts +2 -2
  13. package/dist/experimental/memory/session/index.d.ts +153 -82
  14. package/dist/experimental/memory/session/index.js +257 -24
  15. package/dist/experimental/memory/session/index.js.map +1 -1
  16. package/dist/experimental/memory/utils/index.d.ts +1 -1
  17. package/dist/experimental/memory/utils/index.js +1 -1
  18. package/dist/{index-BtHngIIG.d.ts → index-BPkkIqMn.d.ts} +204 -74
  19. package/dist/{index-Ua2Nfvbm.d.ts → index-DDSX-g7W.d.ts} +11 -1
  20. package/dist/index.d.ts +30 -26
  21. package/dist/index.js +2 -3049
  22. package/dist/{internal_context-DT8RxmAN.d.ts → internal_context-DuQZFvWI.d.ts} +1 -1
  23. package/dist/internal_context.d.ts +1 -1
  24. package/dist/mcp/client.d.ts +2 -2
  25. package/dist/mcp/client.js +1 -1
  26. package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
  27. package/dist/mcp/index.d.ts +1 -1
  28. package/dist/mcp/index.js +2 -2
  29. package/dist/observability/index.d.ts +1 -1
  30. package/dist/react.d.ts +3 -1
  31. package/dist/react.js +3 -0
  32. package/dist/react.js.map +1 -1
  33. package/dist/{retries-DXMQGhG3.d.ts → retries-B_CN5KM9.d.ts} +1 -1
  34. package/dist/retries.d.ts +1 -1
  35. package/dist/{serializable-8Jt1B04R.d.ts → serializable-DGdO8CDh.d.ts} +1 -1
  36. package/dist/serializable.d.ts +1 -1
  37. package/dist/src-B8NZxxsO.js +3217 -0
  38. package/dist/src-B8NZxxsO.js.map +1 -0
  39. package/dist/{types-C-m0II8i.d.ts → types-B9A8AU7B.d.ts} +1 -1
  40. package/dist/types.d.ts +1 -1
  41. package/dist/{workflow-types-CZNXKj_D.d.ts → workflow-types-XmOkuI7A.d.ts} +1 -1
  42. package/dist/workflow-types.d.ts +1 -1
  43. package/dist/workflows.d.ts +2 -2
  44. package/dist/workflows.js +1 -1
  45. package/package.json +12 -16
  46. package/dist/client-BwgM3cRz.js.map +0 -1
  47. package/dist/experimental/forever.d.ts +0 -64
  48. package/dist/experimental/forever.js +0 -338
  49. package/dist/experimental/forever.js.map +0 -1
  50. package/dist/index.js.map +0 -1
@@ -307,7 +307,8 @@ declare class ResumableStream {
307
307
  replayChunks(connection: Connection, requestId: string): string | null;
308
308
  /**
309
309
  * Restore active stream state if the agent was restarted during streaming.
310
- * Validates stream freshness to avoid sending stale resume notifications.
310
+ * All streams are restored regardless of age — stale cleanup happens
311
+ * lazily in _maybeCleanupOldStreams after recovery has had its chance.
311
312
  */
312
313
  restore(): void;
313
314
  /**
@@ -450,5 +451,153 @@ declare class ContinuationState {
450
451
  activateDeferred(generateRequestId: () => string): ContinuationPending | null;
451
452
  }
452
453
  //#endregion
453
- export { type BroadcastStreamEvent, type BroadcastStreamState, type TransitionResult as BroadcastTransitionResult, CHAT_MESSAGE_TYPES, type ChunkAction, type ChunkResult, type ClientToolSchema, type ContinuationConnection, type ContinuationDeferred, type ContinuationPending, ContinuationState, type EnqueueOptions, type MessagePart, type MessageParts, ROW_MAX_BYTES, ResumableStream, type SqlTaggedTemplate, StreamAccumulator, type StreamAccumulatorOptions, type StreamChunkData, TurnQueue, type TurnResult, applyChunkToParts, transition as broadcastTransition, byteLength, createToolsFromClientSchemas, enforceRowSizeLimit, sanitizeMessage };
454
+ //#region src/chat/abort-registry.d.ts
455
+ /**
456
+ * AbortRegistry — manages per-request AbortControllers.
457
+ *
458
+ * Shared between AIChatAgent and Think for chat turn cancellation.
459
+ * Each request gets its own AbortController keyed by request ID.
460
+ * Controllers are created lazily on first signal access.
461
+ */
462
+ declare class AbortRegistry {
463
+ private controllers;
464
+ /**
465
+ * Get or create an AbortController for the given ID and return its signal.
466
+ * Creates the controller lazily on first access.
467
+ */
468
+ getSignal(id: string): AbortSignal | undefined;
469
+ /**
470
+ * Get the signal for an existing controller without creating one.
471
+ * Returns undefined if no controller exists for this ID.
472
+ */
473
+ getExistingSignal(id: string): AbortSignal | undefined;
474
+ /** Cancel a specific request by aborting its controller. */
475
+ cancel(id: string): void;
476
+ /** Remove a controller after the request completes. */
477
+ remove(id: string): void;
478
+ /** Abort all pending requests and clear the registry. */
479
+ destroyAll(): void;
480
+ /** Check if a controller exists for the given ID. */
481
+ has(id: string): boolean;
482
+ /** Number of tracked controllers. */
483
+ get size(): number;
484
+ }
485
+ //#endregion
486
+ //#region src/chat/tool-state.d.ts
487
+ /**
488
+ * Tool State — shared update builders and applicator for tool part state changes.
489
+ *
490
+ * Used by both AIChatAgent and Think to apply tool results and approvals
491
+ * to message parts. Each agent handles find-message, persist, and broadcast
492
+ * in their own way; this module provides the state matching and update logic.
493
+ */
494
+ /**
495
+ * Describes an update to apply to a tool part.
496
+ */
497
+ type ToolPartUpdate = {
498
+ toolCallId: string;
499
+ matchStates: string[];
500
+ apply: (part: Record<string, unknown>) => Record<string, unknown>;
501
+ };
502
+ /**
503
+ * Apply a tool part update to a parts array.
504
+ * Finds the first part matching `update.toolCallId` in one of `update.matchStates`,
505
+ * applies the update immutably, and returns the new parts array with the index.
506
+ *
507
+ * Returns `null` if no matching part was found.
508
+ */
509
+ declare function applyToolUpdate(parts: Array<Record<string, unknown>>, update: ToolPartUpdate): {
510
+ parts: Array<Record<string, unknown>>;
511
+ index: number;
512
+ } | null;
513
+ /**
514
+ * Build an update descriptor for applying a tool result.
515
+ *
516
+ * Matches parts in `input-available`, `approval-requested`, or `approval-responded` state.
517
+ * Sets state to `output-available` (with output) or `output-error` (with errorText).
518
+ */
519
+ declare function toolResultUpdate(toolCallId: string, output: unknown, overrideState?: "output-error", errorText?: string): ToolPartUpdate;
520
+ /**
521
+ * Build an update descriptor for applying a tool approval.
522
+ *
523
+ * Matches parts in `input-available` or `approval-requested` state.
524
+ * Sets state to `approval-responded` (if approved) or `output-denied` (if denied).
525
+ */
526
+ declare function toolApprovalUpdate(toolCallId: string, approved: boolean): ToolPartUpdate;
527
+ //#endregion
528
+ //#region src/chat/parse-protocol.d.ts
529
+ /**
530
+ * Protocol Message Parser — typed parsing of cf_agent_chat_* WebSocket messages.
531
+ *
532
+ * Parses raw WebSocket messages into a discriminated union of protocol events.
533
+ * Both AIChatAgent and Think can use this instead of manual JSON.parse + type checking.
534
+ */
535
+ /**
536
+ * Discriminated union of all incoming chat protocol events.
537
+ *
538
+ * Each agent handles the events it cares about and ignores the rest.
539
+ * Returns `null` for non-JSON messages or unrecognized types.
540
+ */
541
+ type ChatProtocolEvent = {
542
+ type: "chat-request";
543
+ id: string;
544
+ init: {
545
+ method?: string;
546
+ body?: string;
547
+ [key: string]: unknown;
548
+ };
549
+ } | {
550
+ type: "clear";
551
+ } | {
552
+ type: "cancel";
553
+ id: string;
554
+ } | {
555
+ type: "tool-result";
556
+ toolCallId: string;
557
+ toolName: string;
558
+ output: unknown;
559
+ state?: string;
560
+ errorText?: string;
561
+ autoContinue?: boolean;
562
+ clientTools?: Array<{
563
+ name: string;
564
+ description?: string;
565
+ parameters?: unknown;
566
+ }>;
567
+ } | {
568
+ type: "tool-approval";
569
+ toolCallId: string;
570
+ approved: boolean;
571
+ autoContinue?: boolean;
572
+ } | {
573
+ type: "stream-resume-request";
574
+ } | {
575
+ type: "stream-resume-ack";
576
+ id: string;
577
+ } | {
578
+ type: "messages";
579
+ messages: unknown[];
580
+ };
581
+ /**
582
+ * Parse a raw WebSocket message string into a typed protocol event.
583
+ *
584
+ * Returns `null` if the message is not valid JSON or not a recognized
585
+ * protocol message type. Callers should fall through to the user's
586
+ * `onMessage` handler when `null` is returned.
587
+ *
588
+ * @example
589
+ * ```typescript
590
+ * const event = parseProtocolMessage(rawMessage);
591
+ * if (!event) return userOnMessage(connection, rawMessage);
592
+ *
593
+ * switch (event.type) {
594
+ * case "chat-request": { ... }
595
+ * case "clear": { ... }
596
+ * case "tool-result": { ... }
597
+ * }
598
+ * ```
599
+ */
600
+ declare function parseProtocolMessage(raw: string): ChatProtocolEvent | null;
601
+ //#endregion
602
+ export { AbortRegistry, type BroadcastStreamEvent, type BroadcastStreamState, type TransitionResult as BroadcastTransitionResult, CHAT_MESSAGE_TYPES, type ChatProtocolEvent, type ChunkAction, type ChunkResult, type ClientToolSchema, type ContinuationConnection, type ContinuationDeferred, type ContinuationPending, ContinuationState, type EnqueueOptions, type MessagePart, type MessageParts, ROW_MAX_BYTES, ResumableStream, type SqlTaggedTemplate, StreamAccumulator, type StreamAccumulatorOptions, type StreamChunkData, type ToolPartUpdate, TurnQueue, type TurnResult, applyChunkToParts, applyToolUpdate, transition as broadcastTransition, byteLength, createToolsFromClientSchemas, enforceRowSizeLimit, parseProtocolMessage, sanitizeMessage, toolApprovalUpdate, toolResultUpdate };
454
603
  //# sourceMappingURL=index.d.ts.map
@@ -657,8 +657,6 @@ const CHAT_MESSAGE_TYPES = {
657
657
  const CHUNK_BUFFER_SIZE = 10;
658
658
  /** Maximum buffer size to prevent memory issues on rapid reconnections */
659
659
  const CHUNK_BUFFER_MAX_SIZE = 100;
660
- /** Maximum age for a "streaming" stream before considering it stale (ms) - 5 minutes */
661
- const STREAM_STALE_THRESHOLD_MS = 300 * 1e3;
662
660
  /** Default cleanup interval for old streams (ms) - every 10 minutes */
663
661
  const CLEANUP_INTERVAL_MS = 600 * 1e3;
664
662
  /** Default age threshold for cleaning up completed streams (ms) - 24 hours */
@@ -870,7 +868,8 @@ var ResumableStream = class ResumableStream {
870
868
  }
871
869
  /**
872
870
  * Restore active stream state if the agent was restarted during streaming.
873
- * Validates stream freshness to avoid sending stale resume notifications.
871
+ * All streams are restored regardless of age — stale cleanup happens
872
+ * lazily in _maybeCleanupOldStreams after recovery has had its chance.
874
873
  */
875
874
  restore() {
876
875
  const activeStreams = this.sql`
@@ -881,13 +880,6 @@ var ResumableStream = class ResumableStream {
881
880
  `;
882
881
  if (activeStreams && activeStreams.length > 0) {
883
882
  const stream = activeStreams[0];
884
- const streamAge = Date.now() - stream.created_at;
885
- if (streamAge > STREAM_STALE_THRESHOLD_MS) {
886
- this.sql`delete from cf_ai_chat_stream_chunks where stream_id = ${stream.id}`;
887
- this.sql`delete from cf_ai_chat_stream_metadata where id = ${stream.id}`;
888
- console.warn(`[ResumableStream] Deleted stale stream ${stream.id} (age: ${Math.round(streamAge / 1e3)}s)`);
889
- return;
890
- }
891
883
  this._activeStreamId = stream.id;
892
884
  this._activeRequestId = stream.request_id;
893
885
  const lastChunk = this.sql`
@@ -934,6 +926,17 @@ var ResumableStream = class ResumableStream {
934
926
  this.sql`
935
927
  delete from cf_ai_chat_stream_metadata
936
928
  where status in ('completed', 'error') and completed_at < ${cutoff}
929
+ `;
930
+ this.sql`
931
+ delete from cf_ai_chat_stream_chunks
932
+ where stream_id in (
933
+ select id from cf_ai_chat_stream_metadata
934
+ where status = 'streaming' and created_at < ${cutoff}
935
+ )
936
+ `;
937
+ this.sql`
938
+ delete from cf_ai_chat_stream_metadata
939
+ where status = 'streaming' and created_at < ${cutoff}
937
940
  `;
938
941
  }
939
942
  /** @internal For testing only */
@@ -1081,6 +1084,202 @@ var ContinuationState = class {
1081
1084
  }
1082
1085
  };
1083
1086
  //#endregion
1084
- export { CHAT_MESSAGE_TYPES, ContinuationState, ROW_MAX_BYTES, ResumableStream, StreamAccumulator, TurnQueue, applyChunkToParts, transition as broadcastTransition, byteLength, createToolsFromClientSchemas, enforceRowSizeLimit, sanitizeMessage };
1087
+ //#region src/chat/abort-registry.ts
1088
+ /**
1089
+ * AbortRegistry — manages per-request AbortControllers.
1090
+ *
1091
+ * Shared between AIChatAgent and Think for chat turn cancellation.
1092
+ * Each request gets its own AbortController keyed by request ID.
1093
+ * Controllers are created lazily on first signal access.
1094
+ */
1095
+ var AbortRegistry = class {
1096
+ constructor() {
1097
+ this.controllers = /* @__PURE__ */ new Map();
1098
+ }
1099
+ /**
1100
+ * Get or create an AbortController for the given ID and return its signal.
1101
+ * Creates the controller lazily on first access.
1102
+ */
1103
+ getSignal(id) {
1104
+ if (typeof id !== "string") return;
1105
+ if (!this.controllers.has(id)) this.controllers.set(id, new AbortController());
1106
+ return this.controllers.get(id).signal;
1107
+ }
1108
+ /**
1109
+ * Get the signal for an existing controller without creating one.
1110
+ * Returns undefined if no controller exists for this ID.
1111
+ */
1112
+ getExistingSignal(id) {
1113
+ return this.controllers.get(id)?.signal;
1114
+ }
1115
+ /** Cancel a specific request by aborting its controller. */
1116
+ cancel(id) {
1117
+ this.controllers.get(id)?.abort();
1118
+ }
1119
+ /** Remove a controller after the request completes. */
1120
+ remove(id) {
1121
+ this.controllers.delete(id);
1122
+ }
1123
+ /** Abort all pending requests and clear the registry. */
1124
+ destroyAll() {
1125
+ for (const controller of this.controllers.values()) controller.abort();
1126
+ this.controllers.clear();
1127
+ }
1128
+ /** Check if a controller exists for the given ID. */
1129
+ has(id) {
1130
+ return this.controllers.has(id);
1131
+ }
1132
+ /** Number of tracked controllers. */
1133
+ get size() {
1134
+ return this.controllers.size;
1135
+ }
1136
+ };
1137
+ //#endregion
1138
+ //#region src/chat/tool-state.ts
1139
+ /**
1140
+ * Apply a tool part update to a parts array.
1141
+ * Finds the first part matching `update.toolCallId` in one of `update.matchStates`,
1142
+ * applies the update immutably, and returns the new parts array with the index.
1143
+ *
1144
+ * Returns `null` if no matching part was found.
1145
+ */
1146
+ function applyToolUpdate(parts, update) {
1147
+ for (let i = 0; i < parts.length; i++) {
1148
+ const part = parts[i];
1149
+ if ("toolCallId" in part && part.toolCallId === update.toolCallId && "state" in part && update.matchStates.includes(part.state)) {
1150
+ const updatedParts = [...parts];
1151
+ updatedParts[i] = update.apply(part);
1152
+ return {
1153
+ parts: updatedParts,
1154
+ index: i
1155
+ };
1156
+ }
1157
+ }
1158
+ return null;
1159
+ }
1160
+ /**
1161
+ * Build an update descriptor for applying a tool result.
1162
+ *
1163
+ * Matches parts in `input-available`, `approval-requested`, or `approval-responded` state.
1164
+ * Sets state to `output-available` (with output) or `output-error` (with errorText).
1165
+ */
1166
+ function toolResultUpdate(toolCallId, output, overrideState, errorText) {
1167
+ return {
1168
+ toolCallId,
1169
+ matchStates: [
1170
+ "input-available",
1171
+ "approval-requested",
1172
+ "approval-responded"
1173
+ ],
1174
+ apply: (part) => ({
1175
+ ...part,
1176
+ ...overrideState === "output-error" ? {
1177
+ state: "output-error",
1178
+ errorText: errorText ?? "Tool execution denied by user"
1179
+ } : {
1180
+ state: "output-available",
1181
+ output,
1182
+ preliminary: false
1183
+ }
1184
+ })
1185
+ };
1186
+ }
1187
+ /**
1188
+ * Build an update descriptor for applying a tool approval.
1189
+ *
1190
+ * Matches parts in `input-available` or `approval-requested` state.
1191
+ * Sets state to `approval-responded` (if approved) or `output-denied` (if denied).
1192
+ */
1193
+ function toolApprovalUpdate(toolCallId, approved) {
1194
+ return {
1195
+ toolCallId,
1196
+ matchStates: ["input-available", "approval-requested"],
1197
+ apply: (part) => ({
1198
+ ...part,
1199
+ state: approved ? "approval-responded" : "output-denied",
1200
+ approval: {
1201
+ ...part.approval,
1202
+ approved
1203
+ }
1204
+ })
1205
+ };
1206
+ }
1207
+ //#endregion
1208
+ //#region src/chat/parse-protocol.ts
1209
+ /**
1210
+ * Protocol Message Parser — typed parsing of cf_agent_chat_* WebSocket messages.
1211
+ *
1212
+ * Parses raw WebSocket messages into a discriminated union of protocol events.
1213
+ * Both AIChatAgent and Think can use this instead of manual JSON.parse + type checking.
1214
+ */
1215
+ /**
1216
+ * Parse a raw WebSocket message string into a typed protocol event.
1217
+ *
1218
+ * Returns `null` if the message is not valid JSON or not a recognized
1219
+ * protocol message type. Callers should fall through to the user's
1220
+ * `onMessage` handler when `null` is returned.
1221
+ *
1222
+ * @example
1223
+ * ```typescript
1224
+ * const event = parseProtocolMessage(rawMessage);
1225
+ * if (!event) return userOnMessage(connection, rawMessage);
1226
+ *
1227
+ * switch (event.type) {
1228
+ * case "chat-request": { ... }
1229
+ * case "clear": { ... }
1230
+ * case "tool-result": { ... }
1231
+ * }
1232
+ * ```
1233
+ */
1234
+ function parseProtocolMessage(raw) {
1235
+ let data;
1236
+ try {
1237
+ data = JSON.parse(raw);
1238
+ } catch {
1239
+ return null;
1240
+ }
1241
+ const wireType = data.type;
1242
+ if (!wireType) return null;
1243
+ switch (wireType) {
1244
+ case CHAT_MESSAGE_TYPES.USE_CHAT_REQUEST: return {
1245
+ type: "chat-request",
1246
+ id: data.id,
1247
+ init: data.init ?? {}
1248
+ };
1249
+ case CHAT_MESSAGE_TYPES.CHAT_CLEAR: return { type: "clear" };
1250
+ case CHAT_MESSAGE_TYPES.CHAT_REQUEST_CANCEL: return {
1251
+ type: "cancel",
1252
+ id: data.id
1253
+ };
1254
+ case CHAT_MESSAGE_TYPES.TOOL_RESULT: return {
1255
+ type: "tool-result",
1256
+ toolCallId: data.toolCallId,
1257
+ toolName: data.toolName ?? "",
1258
+ output: data.output,
1259
+ state: data.state,
1260
+ errorText: data.errorText,
1261
+ autoContinue: data.autoContinue,
1262
+ clientTools: data.clientTools
1263
+ };
1264
+ case CHAT_MESSAGE_TYPES.TOOL_APPROVAL: return {
1265
+ type: "tool-approval",
1266
+ toolCallId: data.toolCallId,
1267
+ approved: data.approved,
1268
+ autoContinue: data.autoContinue
1269
+ };
1270
+ case CHAT_MESSAGE_TYPES.STREAM_RESUME_REQUEST: return { type: "stream-resume-request" };
1271
+ case CHAT_MESSAGE_TYPES.STREAM_RESUME_ACK: return {
1272
+ type: "stream-resume-ack",
1273
+ id: data.id
1274
+ };
1275
+ case CHAT_MESSAGE_TYPES.CHAT_MESSAGES: return {
1276
+ type: "messages",
1277
+ messages: data.messages ?? []
1278
+ };
1279
+ default: return null;
1280
+ }
1281
+ }
1282
+ //#endregion
1283
+ export { AbortRegistry, CHAT_MESSAGE_TYPES, ContinuationState, ROW_MAX_BYTES, ResumableStream, StreamAccumulator, TurnQueue, applyChunkToParts, applyToolUpdate, transition as broadcastTransition, byteLength, createToolsFromClientSchemas, enforceRowSizeLimit, parseProtocolMessage, sanitizeMessage, toolApprovalUpdate, toolResultUpdate };
1085
1284
 
1086
1285
  //# sourceMappingURL=index.js.map