@plotday/twister 0.52.0 → 0.54.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 (219) hide show
  1. package/bin/commands/deploy.js +4 -0
  2. package/bin/commands/deploy.js.map +1 -1
  3. package/bin/templates/AGENTS.template.md +6 -10
  4. package/cli/templates/AGENTS.template.md +6 -10
  5. package/dist/connector.d.ts +179 -10
  6. package/dist/connector.d.ts.map +1 -1
  7. package/dist/connector.js +78 -4
  8. package/dist/connector.js.map +1 -1
  9. package/dist/docs/assets/hierarchy.js +1 -1
  10. package/dist/docs/assets/navigation.js +1 -1
  11. package/dist/docs/assets/search.js +1 -1
  12. package/dist/docs/classes/index.Connector.html +74 -26
  13. package/dist/docs/classes/index.FileNotFoundError.html +2 -0
  14. package/dist/docs/classes/index.Files.html +16 -0
  15. package/dist/docs/classes/index.Imap.html +1 -1
  16. package/dist/docs/classes/index.Options.html +1 -1
  17. package/dist/docs/classes/index.Smtp.html +1 -1
  18. package/dist/docs/classes/tool.ITool.html +1 -1
  19. package/dist/docs/classes/tools_ai.AI.html +7 -5
  20. package/dist/docs/classes/tools_callbacks.Callbacks.html +1 -1
  21. package/dist/docs/classes/tools_integrations.Integrations.html +17 -23
  22. package/dist/docs/classes/tools_network.Network.html +1 -1
  23. package/dist/docs/classes/tools_plot.Plot.html +62 -56
  24. package/dist/docs/classes/tools_store.Store.html +1 -1
  25. package/dist/docs/classes/tools_tasks.Tasks.html +1 -1
  26. package/dist/docs/classes/tools_twists.Twists.html +2 -2
  27. package/dist/docs/classes/twist.Twist.html +3 -3
  28. package/dist/docs/documents/Building_Connectors.html +1 -1
  29. package/dist/docs/enums/plot.ActionType.html +10 -8
  30. package/dist/docs/enums/plot.ActorType.html +4 -4
  31. package/dist/docs/enums/plot.ConferencingProvider.html +6 -6
  32. package/dist/docs/enums/plot.ThemeColor.html +10 -10
  33. package/dist/docs/enums/tag.Tag.html +16 -46
  34. package/dist/docs/enums/tools_ai.AIModel.html +2 -2
  35. package/dist/docs/enums/tools_integrations.AuthProvider.html +13 -13
  36. package/dist/docs/enums/{tools_plot.PriorityAccess.html → tools_plot.FocusAccess.html} +6 -6
  37. package/dist/docs/enums/tools_plot.ThreadAccess.html +1 -1
  38. package/dist/docs/hierarchy.html +1 -1
  39. package/dist/docs/interfaces/tools_ai.AIRequest.html +27 -11
  40. package/dist/docs/interfaces/tools_ai.AIResponse.html +9 -9
  41. package/dist/docs/interfaces/tools_ai.FilePart.html +5 -5
  42. package/dist/docs/interfaces/tools_ai.ImagePart.html +4 -4
  43. package/dist/docs/interfaces/tools_ai.ReasoningPart.html +4 -4
  44. package/dist/docs/interfaces/tools_ai.RedactedReasoningPart.html +3 -3
  45. package/dist/docs/interfaces/tools_ai.TextPart.html +3 -3
  46. package/dist/docs/interfaces/tools_ai.ToolCallPart.html +5 -5
  47. package/dist/docs/interfaces/tools_ai.ToolExecutionOptions.html +4 -4
  48. package/dist/docs/interfaces/tools_ai.ToolResultPart.html +5 -5
  49. package/dist/docs/media/AGENTS.md +22 -14
  50. package/dist/docs/modules/index.html +1 -1
  51. package/dist/docs/modules/plot.html +1 -1
  52. package/dist/docs/modules/tools_integrations.html +1 -1
  53. package/dist/docs/modules/tools_plot.html +1 -1
  54. package/dist/docs/types/index.CreateLinkDraft.html +31 -7
  55. package/dist/docs/types/index.NoteWriteBackResult.html +3 -3
  56. package/dist/docs/types/index.ReactionCapabilities.html +17 -0
  57. package/dist/docs/types/index.ResolvedRecipient.html +24 -0
  58. package/dist/docs/types/index.Schedule.html +1 -1
  59. package/dist/docs/types/plot.Action.html +9 -2
  60. package/dist/docs/types/plot.Actor.html +5 -5
  61. package/dist/docs/types/plot.ActorId.html +1 -1
  62. package/dist/docs/types/plot.Contact.html +4 -4
  63. package/dist/docs/types/plot.ContentType.html +1 -1
  64. package/dist/docs/types/{plot.Priority.html → plot.Focus.html} +14 -11
  65. package/dist/docs/types/plot.FocusUpdate.html +3 -0
  66. package/dist/docs/types/plot.Link.html +16 -16
  67. package/dist/docs/types/plot.LinkUpdate.html +1 -1
  68. package/dist/docs/types/plot.NewActor.html +1 -1
  69. package/dist/docs/types/plot.NewContact.html +1 -1
  70. package/dist/docs/types/plot.NewFocus.html +13 -0
  71. package/dist/docs/types/plot.NewLink.html +6 -6
  72. package/dist/docs/types/plot.NewLinkWithNotes.html +1 -1
  73. package/dist/docs/types/plot.NewNote.html +5 -3
  74. package/dist/docs/types/plot.NewReactions.html +4 -0
  75. package/dist/docs/types/plot.NewTags.html +1 -1
  76. package/dist/docs/types/plot.NewThread.html +6 -4
  77. package/dist/docs/types/plot.NewThreadWithNotes.html +1 -1
  78. package/dist/docs/types/plot.Note.html +2 -2
  79. package/dist/docs/types/plot.NoteUpdate.html +4 -2
  80. package/dist/docs/types/plot.PlanOperation.html +6 -6
  81. package/dist/docs/types/plot.Reaction.html +13 -0
  82. package/dist/docs/types/plot.Reactions.html +3 -0
  83. package/dist/docs/types/plot.Tags.html +1 -1
  84. package/dist/docs/types/plot.Thread.html +1 -1
  85. package/dist/docs/types/plot.ThreadAccessLevel.html +3 -3
  86. package/dist/docs/types/plot.ThreadCommon.html +9 -5
  87. package/dist/docs/types/plot.ThreadFilter.html +2 -2
  88. package/dist/docs/types/plot.ThreadMeta.html +1 -1
  89. package/dist/docs/types/plot.ThreadType.html +4 -4
  90. package/dist/docs/types/plot.ThreadUpdate.html +1 -1
  91. package/dist/docs/types/plot.ThreadWithNotes.html +1 -1
  92. package/dist/docs/types/tools_ai.AIAssistantMessage.html +2 -2
  93. package/dist/docs/types/tools_ai.AICapabilities.html +7 -3
  94. package/dist/docs/types/tools_ai.AIMessage.html +1 -1
  95. package/dist/docs/types/tools_ai.AIOptions.html +2 -2
  96. package/dist/docs/types/tools_ai.AISource.html +1 -1
  97. package/dist/docs/types/tools_ai.AISystemMessage.html +2 -2
  98. package/dist/docs/types/tools_ai.AITool.html +10 -9
  99. package/dist/docs/types/tools_ai.AIToolMessage.html +2 -2
  100. package/dist/docs/types/tools_ai.AIToolSet.html +1 -1
  101. package/dist/docs/types/tools_ai.AIUsage.html +5 -5
  102. package/dist/docs/types/tools_ai.AIUserMessage.html +2 -2
  103. package/dist/docs/types/tools_ai.DataContent.html +1 -1
  104. package/dist/docs/types/tools_ai.ModelPreferences.html +4 -4
  105. package/dist/docs/types/tools_integrations.ArchiveLinkFilter.html +5 -5
  106. package/dist/docs/types/tools_integrations.AuthToken.html +4 -4
  107. package/dist/docs/types/tools_integrations.Authorization.html +4 -4
  108. package/dist/docs/types/tools_integrations.Channel.html +5 -5
  109. package/dist/docs/types/tools_integrations.ComposeConfig.html +35 -0
  110. package/dist/docs/types/tools_integrations.ContactRoleConfig.html +14 -0
  111. package/dist/docs/types/tools_integrations.LinkTypeConfig.html +55 -28
  112. package/dist/docs/types/tools_integrations.SyncContext.html +3 -3
  113. package/dist/docs/types/tools_plot.SearchOptions.html +5 -6
  114. package/dist/docs/types/tools_twists.TwistPermissions.html +1 -1
  115. package/dist/llm-docs/connector.d.ts +1 -1
  116. package/dist/llm-docs/connector.d.ts.map +1 -1
  117. package/dist/llm-docs/connector.js +1 -1
  118. package/dist/llm-docs/connector.js.map +1 -1
  119. package/dist/llm-docs/index.d.ts.map +1 -1
  120. package/dist/llm-docs/index.js +2 -0
  121. package/dist/llm-docs/index.js.map +1 -1
  122. package/dist/llm-docs/plot.d.ts +1 -1
  123. package/dist/llm-docs/plot.d.ts.map +1 -1
  124. package/dist/llm-docs/plot.js +1 -1
  125. package/dist/llm-docs/plot.js.map +1 -1
  126. package/dist/llm-docs/schedule.d.ts +1 -1
  127. package/dist/llm-docs/schedule.d.ts.map +1 -1
  128. package/dist/llm-docs/schedule.js +1 -1
  129. package/dist/llm-docs/schedule.js.map +1 -1
  130. package/dist/llm-docs/tag.d.ts +1 -1
  131. package/dist/llm-docs/tag.d.ts.map +1 -1
  132. package/dist/llm-docs/tag.js +1 -1
  133. package/dist/llm-docs/tag.js.map +1 -1
  134. package/dist/llm-docs/tools/ai.d.ts +1 -1
  135. package/dist/llm-docs/tools/ai.d.ts.map +1 -1
  136. package/dist/llm-docs/tools/ai.js +1 -1
  137. package/dist/llm-docs/tools/ai.js.map +1 -1
  138. package/dist/llm-docs/tools/files.d.ts +9 -0
  139. package/dist/llm-docs/tools/files.d.ts.map +1 -0
  140. package/dist/llm-docs/tools/files.js +8 -0
  141. package/dist/llm-docs/tools/files.js.map +1 -0
  142. package/dist/llm-docs/tools/integrations.d.ts +1 -1
  143. package/dist/llm-docs/tools/integrations.d.ts.map +1 -1
  144. package/dist/llm-docs/tools/integrations.js +1 -1
  145. package/dist/llm-docs/tools/integrations.js.map +1 -1
  146. package/dist/llm-docs/tools/plot.d.ts +1 -1
  147. package/dist/llm-docs/tools/plot.d.ts.map +1 -1
  148. package/dist/llm-docs/tools/plot.js +1 -1
  149. package/dist/llm-docs/tools/plot.js.map +1 -1
  150. package/dist/llm-docs/tools/twists.d.ts +1 -1
  151. package/dist/llm-docs/tools/twists.d.ts.map +1 -1
  152. package/dist/llm-docs/tools/twists.js +1 -1
  153. package/dist/llm-docs/tools/twists.js.map +1 -1
  154. package/dist/llm-docs/twist-guide-template.d.ts +1 -1
  155. package/dist/llm-docs/twist-guide-template.d.ts.map +1 -1
  156. package/dist/llm-docs/twist-guide-template.js +1 -1
  157. package/dist/llm-docs/twist-guide-template.js.map +1 -1
  158. package/dist/llm-docs/twist.d.ts +1 -1
  159. package/dist/llm-docs/twist.d.ts.map +1 -1
  160. package/dist/llm-docs/twist.js +1 -1
  161. package/dist/llm-docs/twist.js.map +1 -1
  162. package/dist/plot.d.ts +146 -85
  163. package/dist/plot.d.ts.map +1 -1
  164. package/dist/plot.js +3 -1
  165. package/dist/plot.js.map +1 -1
  166. package/dist/schedule.d.ts +1 -1
  167. package/dist/tag.d.ts +17 -43
  168. package/dist/tag.d.ts.map +1 -1
  169. package/dist/tag.js +17 -46
  170. package/dist/tag.js.map +1 -1
  171. package/dist/tools/ai.d.ts +46 -10
  172. package/dist/tools/ai.d.ts.map +1 -1
  173. package/dist/tools/ai.js.map +1 -1
  174. package/dist/tools/files.d.ts +33 -0
  175. package/dist/tools/files.d.ts.map +1 -0
  176. package/dist/tools/files.js +22 -0
  177. package/dist/tools/files.js.map +1 -0
  178. package/dist/tools/index.d.ts +1 -0
  179. package/dist/tools/index.d.ts.map +1 -1
  180. package/dist/tools/index.js +1 -0
  181. package/dist/tools/index.js.map +1 -1
  182. package/dist/tools/integrations.d.ts +130 -50
  183. package/dist/tools/integrations.d.ts.map +1 -1
  184. package/dist/tools/integrations.js.map +1 -1
  185. package/dist/tools/plot.d.ts +66 -56
  186. package/dist/tools/plot.d.ts.map +1 -1
  187. package/dist/tools/plot.js +14 -14
  188. package/dist/tools/plot.js.map +1 -1
  189. package/dist/tools/twists.d.ts +2 -2
  190. package/dist/twist-guide.d.ts +1 -1
  191. package/dist/twist-guide.d.ts.map +1 -1
  192. package/dist/twist.d.ts +3 -3
  193. package/dist/twist.js +3 -3
  194. package/package.json +6 -1
  195. package/src/connector.ts +182 -10
  196. package/src/llm-docs/connector.ts +1 -1
  197. package/src/llm-docs/index.ts +2 -0
  198. package/src/llm-docs/plot.ts +1 -1
  199. package/src/llm-docs/schedule.ts +1 -1
  200. package/src/llm-docs/tag.ts +1 -1
  201. package/src/llm-docs/tools/ai.ts +1 -1
  202. package/src/llm-docs/tools/files.ts +8 -0
  203. package/src/llm-docs/tools/integrations.ts +1 -1
  204. package/src/llm-docs/tools/plot.ts +1 -1
  205. package/src/llm-docs/tools/twists.ts +1 -1
  206. package/src/llm-docs/twist-guide-template.ts +1 -1
  207. package/src/llm-docs/twist.ts +1 -1
  208. package/src/plot.ts +156 -75
  209. package/src/schedule.ts +1 -1
  210. package/src/tag.ts +17 -48
  211. package/src/tools/ai.ts +46 -10
  212. package/src/tools/files.ts +37 -0
  213. package/src/tools/index.ts +1 -0
  214. package/src/tools/integrations.ts +131 -61
  215. package/src/tools/plot.ts +69 -59
  216. package/src/tools/twists.ts +2 -2
  217. package/src/twist.ts +3 -3
  218. package/dist/docs/types/plot.NewPriority.html +0 -15
  219. package/dist/docs/types/plot.PriorityUpdate.html +0 -5
@@ -4,5 +4,5 @@
4
4
  * This file is auto-generated during build. Do not edit manually.
5
5
  * Generated from: prebuild.ts
6
6
  */
7
- export default "import type { NewSchedule, NewScheduleOccurrence, Schedule } from \"./schedule\";\nimport { type Tag } from \"./tag\";\nimport { type Callback } from \"./tools/callbacks\";\nimport { type AuthProvider } from \"./tools/integrations\";\nimport { type JSONValue } from \"./utils/types\";\nimport { Uuid } from \"./utils/uuid\";\n\nexport { Tag } from \"./tag\";\nexport { Uuid } from \"./utils/uuid\";\nexport { type JSONValue } from \"./utils/types\";\nexport { type AuthProvider } from \"./tools/integrations\";\n\n/**\n * @fileoverview\n * Core Plot entity types for working with threads, notes, priorities, and contacts.\n *\n * ## Type Pattern: Null vs Undefined Semantics\n *\n * Plot entity types use a consistent pattern to distinguish between missing, unset, and explicitly cleared values:\n *\n * ### Entity Types (Thread, Priority, Note, Actor)\n * - **Required fields**: No `?`, cannot be `undefined`\n * - Example: `id: Uuid`, `title: string`\n * - **Nullable fields**: Use `| null` to allow explicit clearing\n * - Example: `assignee: ActorId | null`, `done: Date | null`\n * - `null` = field is explicitly unset/cleared\n * - Non-null value = field has a value\n * - **Optional nullable fields**: Use `?` with `| null` for permission-based access\n * - Example: `email?: string | null`, `name?: string | null`\n * - `undefined` = field not included (e.g., no permission to access)\n * - `null` = field included but not set\n * - Value = field has a value\n *\n * ### New* Types (NewThread, NewNote, NewPriority)\n * Used for creating or updating entities. Support partial updates by distinguishing omitted vs cleared fields:\n * - **Required fields**: Must be provided (no `?`)\n * - Example: `title: string` in NewPriority\n * - **Optional fields**: Use `?` to make them optional\n * - Example: `title?: string`, `author?: NewActor`\n * - `undefined` (omitted) = don't set/update this field\n * - Provided value = set/update this field\n * - **Optional nullable fields**: Use `?` with `| null` to support clearing\n * - Example: `assignee?: NewActor | null`\n * - `undefined` (omitted) = don't change assignee\n * - `null` = clear the assignee\n * - NewActor = set/update the assignee\n *\n * This pattern allows API consumers to:\n * 1. Omit fields they don't want to change (undefined)\n * 2. Explicitly clear fields by setting to null\n * 3. Set or update fields by providing values\n *\n * @example\n * ```typescript\n * // Creating a new thread\n * const newThread: NewThread = {\n * title: \"Review pull request\",\n * };\n *\n * // Updating a thread - only change what's specified\n * const update: ThreadUpdate = {\n * id: threadId,\n * archived: true,\n * };\n * ```\n */\n\n/**\n * Represents a unique user, contact, or twist in Plot.\n *\n * ActorIds are used throughout Plot for:\n * - Activity authors and assignees\n * - Tag creators (actor_id in activity_tag/note_tag)\n * - Mentions in activities and notes\n * - Any entity that can perform actions in Plot\n */\nexport type ActorId = string & { readonly __brand: \"ActorId\" };\n\n/**\n * Theme colors for priorities.\n */\nexport enum ThemeColor {\n /** Catalyst - Green */\n Catalyst = 0,\n /** Call to Adventure - Blue */\n CallToAdventure = 1,\n /** Rising Action - Purple */\n RisingAction = 2,\n /** Momentum - Pink-Purple */\n Momentum = 3,\n /** Turning Point - Pink */\n TurningPoint = 4,\n /** Breakthrough - Orange */\n Breakthrough = 5,\n /** Climax - Olive */\n Climax = 6,\n /** Resolution - Blue-Gray */\n Resolution = 7,\n}\n\n/**\n * Represents a priority context within Plot.\n *\n * Priorities are similar to projects in other apps. All Activity is in a Priority.\n * Priorities can be nested.\n */\nexport type Priority = {\n /** Unique identifier for the priority */\n id: Uuid;\n /** Human-readable title for the priority */\n title: string;\n /** Whether this priority has been archived */\n archived: boolean;\n /**\n * Optional key for referencing this priority.\n * Keys are unique per priority tree (a user's personal priorities or the root of a shared priority).\n */\n key: string | null;\n /** Optional theme color for the priority (0-7). If not set, inherits from parent or defaults to 7 (Resolution). */\n color: ThemeColor | null;\n};\n\n/**\n * Type for creating new priorities.\n *\n * Supports multiple creation patterns:\n * - Provide a specific UUID for the priority\n * - Provide a key for upsert within the user's priorities\n * - Omit both to auto-generate a new UUID\n *\n * Optionally specify a parent priority by ID or key for hierarchical structures.\n */\nexport type NewPriority = Pick<Priority, \"title\"> &\n Partial<Omit<Priority, \"id\" | \"title\">> &\n (\n | {\n /**\n * Unique identifier for the priority, generated by Uuid.Generate().\n * Specifying an ID allows tools to track and upsert priorities.\n */\n id: Uuid;\n }\n | {\n /**\n * Unique key for the priority within the user's priorities.\n * Can be used to upsert without knowing the UUID.\n * For example, \"@plot\" identifies the Plot priority.\n */\n key: string;\n }\n | {\n /* Neither id nor key is required. An id will be generated and returned. */\n }\n ) & {\n /** Add the new priority as the child of another priority */\n parent?: { id: Uuid } | { key: string };\n };\n\n/**\n * Type for updating existing priorities.\n * Must provide either id or key to identify the priority to update.\n * Set `parent` to move the priority under a new parent (requires PriorityAccess.Full).\n */\nexport type PriorityUpdate = ({ id: Uuid } | { key: string }) &\n Partial<Pick<Priority, \"title\" | \"archived\">> & {\n /** Move the priority under a new parent. Requires PriorityAccess.Full. */\n parent?: { id: Uuid } | { key: string };\n };\n\n/**\n * Enumeration of supported action types.\n *\n * Different action types have different behaviors when clicked by users\n * and may require different rendering approaches.\n */\nexport enum ActionType {\n /** External web links that open in browser */\n external = \"external\",\n /** Authentication flows for connecting services */\n auth = \"auth\",\n /** Callback actions that trigger twist methods when clicked */\n callback = \"callback\",\n /** Video conferencing links with provider-specific handling */\n conferencing = \"conferencing\",\n /** File attachment links stored in R2 */\n file = \"file\",\n /** Thread reference links for navigating to related threads */\n thread = \"thread\",\n /** Structured plan of operations for user approval */\n plan = \"plan\",\n}\n\n/**\n * Video conferencing providers for conferencing links.\n *\n * Used to identify the conferencing platform and provide\n * provider-specific UI elements (titles, icons, etc.).\n */\nexport enum ConferencingProvider {\n /** Google Meet */\n googleMeet = \"googleMeet\",\n /** Zoom */\n zoom = \"zoom\",\n /** Microsoft Teams */\n microsoftTeams = \"microsoftTeams\",\n /** Cisco Webex */\n webex = \"webex\",\n /** Other or unknown conferencing provider */\n other = \"other\",\n}\n\n/**\n * Represents a clickable action attached to a thread.\n *\n * Thread actions are rendered as buttons that enable user interaction with threads.\n * Different action types have specific behaviors and required fields for proper functionality.\n *\n * @example\n * ```typescript\n * // External action - opens URL in browser\n * const externalAction: Action = {\n * type: ActionType.external,\n * title: \"Open in Google Calendar\",\n * url: \"https://calendar.google.com/event/123\",\n * };\n *\n * // Conferencing action - opens video conference with provider info\n * const conferencingAction: Action = {\n * type: ActionType.conferencing,\n * url: \"https://meet.google.com/abc-defg-hij\",\n * provider: ConferencingProvider.googleMeet,\n * };\n *\n * // Integrations action - initiates OAuth flow\n * const authAction: Action = {\n * type: ActionType.auth,\n * title: \"Continue with Google\",\n * provider: AuthProvider.Google,\n * scopes: [\"https://www.googleapis.com/auth/calendar.readonly\"],\n * callback: \"callback-token-for-auth-completion\"\n * };\n *\n * // Callback action - triggers a twist method\n * const callbackAction: Action = {\n * type: ActionType.callback,\n * title: \"📅 Primary Calendar\",\n * token: \"callback-token-here\"\n * };\n * ```\n */\nexport type Action =\n | {\n /** External web link that opens in browser */\n type: ActionType.external;\n /** Display text for the action button */\n title: string;\n /** URL to open when clicked */\n url: string;\n }\n | {\n /** Video conferencing action with provider-specific handling */\n type: ActionType.conferencing;\n /** URL to join the conference */\n url: string;\n /** Conferencing provider for UI customization */\n provider: ConferencingProvider;\n }\n | {\n /** Authentication action that initiates an OAuth flow */\n type: ActionType.auth;\n /** Display text for the auth button */\n title: string;\n /** OAuth provider (e.g., \"google\", \"microsoft\") */\n provider: string;\n /** Array of OAuth scopes to request */\n scopes: string[];\n /** Callback token for auth completion notification */\n callback: Callback;\n }\n | {\n /** Callback action that triggers a twist method when clicked */\n type: ActionType.callback;\n /** Display text for the callback button */\n title: string;\n /** Token identifying the callback to execute */\n callback: Callback;\n }\n | {\n /** File attachment action stored in R2 */\n type: ActionType.file;\n /** Unique identifier for the stored file */\n fileId: string;\n /** Original filename */\n fileName: string;\n /** File size in bytes */\n fileSize: number;\n /** MIME type of the file */\n mimeType: string;\n /** Intrinsic width of the image in pixels (only for image files) */\n imageWidth?: number | null;\n /** Intrinsic height of the image in pixels (only for image files) */\n imageHeight?: number | null;\n }\n | {\n /** Thread reference action for navigating to a related thread */\n type: ActionType.thread;\n /** UUID of the referenced thread */\n threadId: Uuid;\n }\n | {\n /** Structured plan of operations for user approval */\n type: ActionType.plan;\n /** Human-readable summary of the plan */\n title: string;\n /** Operations to execute on approval */\n operations: PlanOperation[];\n /** Callback invoked with (action, approved: boolean) */\n callback: Callback;\n };\n\n/**\n * Represents metadata about a thread, typically from an external system.\n *\n * Thread metadata enables storing additional information about threads,\n * which is useful for synchronization, linking back to external systems,\n * and storing tool-specific data.\n *\n * Must be valid JSON data (strings, numbers, booleans, null, objects, arrays).\n * Functions and other non-JSON values are not supported.\n *\n * @example\n * ```typescript\n * // Calendar event metadata\n * await plot.createThread({\n * title: \"Team Meeting\",\n * meta: {\n * calendarId: \"primary\",\n * htmlLink: \"https://calendar.google.com/event/abc123\",\n * conferenceData: { ... }\n * }\n * });\n *\n * // Project issue metadata\n * await plot.createThread({\n * title: \"Fix login bug\",\n * meta: {\n * projectId: \"TEAM\",\n * issueNumber: 123,\n * url: \"https://linear.app/team/issue/TEAM-123\"\n * }\n * });\n * ```\n */\nexport type ThreadMeta = {\n /** Source-specific properties and metadata */\n [key: string]: JSONValue;\n};\n\n/**\n * Thread sub-type that determines the thread's icon and category.\n * Available types depend on whether the priority is shared:\n * - Private priorities: \"action\" (default for tasks), \"notes\" (default), \"idea\", \"goal\", \"decision\"\n * - Shared priorities: all above plus \"discussion\" (default), \"announcement\", \"ask\"\n */\nexport type ThreadType =\n | \"action\"\n | \"notes\"\n | \"idea\"\n | \"goal\"\n | \"decision\"\n | \"discussion\"\n | \"announcement\"\n | \"ask\";\n\n/**\n * Tags on an item, along with the actors who added each tag.\n */\nexport type Tags = { [K in Tag]?: ActorId[] };\n\n/**\n * A set of tags to add to an item, along with the actors adding each tag.\n */\nexport type NewTags = { [K in Tag]?: NewActor[] };\n\n/**\n * Thread access level determining visibility.\n * - \"public\": Visible to all users with priority access\n * - \"members\": Visible to priority members (default for shared priorities)\n * - \"private\": Visible only to creator and contacts listed in accessContacts\n */\nexport type ThreadAccessLevel = \"public\" | \"members\" | \"private\";\n\n/**\n * Common fields shared by both Thread and Note entities.\n */\nexport type ThreadCommon = {\n /** Unique identifier for the thread */\n id: Uuid;\n /**\n * When this item was created.\n *\n * **For sources:** Set this to the external system's timestamp (e.g., email\n * sent date, comment creation date), NOT the sync time. If omitted, defaults\n * to the current time, which is almost never correct for synced data.\n */\n created: Date;\n /** Whether this thread has been archived */\n archived: boolean;\n /** Tags attached to this thread. Maps tag ID to array of actor IDs who added that tag. */\n tags: Tags;\n};\n\n/**\n * Fields on a Thread entity.\n * Threads are simple containers for links and notes.\n */\ntype ThreadFields = ThreadCommon & {\n /** The display title/summary of the thread */\n title: string;\n /** The priority context this thread belongs to */\n priority: Priority;\n /** The thread's sub-type/category. Determines the displayed icon. */\n type: ThreadType | null;\n /** Thread access level: \"public\", \"members\", or \"private\" */\n access: ThreadAccessLevel;\n /** Contacts who can see a private thread (empty array for creator-only). Only meaningful when access is \"private\". */\n accessContacts: Contact[];\n /** The schedule associated with this thread, if any */\n schedule?: Schedule;\n /** Source-specific metadata from the thread's link, populated on callbacks */\n meta?: ThreadMeta;\n};\n\nexport type Thread = ThreadFields;\n\nexport type ThreadWithNotes = Thread & {\n notes: Note[];\n};\n\nexport type NewThreadWithNotes = NewThread & {\n notes: Omit<NewNote, \"thread\">[];\n};\n\n/**\n * Type for creating new threads.\n *\n * Threads are simple containers. All other fields are optional.\n *\n * @example\n * ```typescript\n * const thread: NewThread = {\n * title: \"Review pull request\"\n * };\n * ```\n */\nexport type NewThread = Partial<\n Omit<ThreadFields, \"priority\" | \"tags\" | \"id\" | \"accessContacts\">\n> &\n (\n | {\n /** Unique identifier for the thread, generated by Uuid.Generate(). */\n id: Uuid;\n }\n | {\n /* id is optional. An id will be generated and returned. */\n }\n ) &\n {\n /** Explicit priority - disables automatic priority matching. When omitted, the server classifies the thread using the user's priority rules. */\n priority?: Pick<Priority, \"id\">;\n } & {\n /**\n * All tags to set on the new thread.\n */\n tags?: NewTags;\n\n /**\n * The thread's sub-type/category. Sets the thread's icon.\n * If omitted, defaults to \"notes\" (private) or \"discussion\" (shared).\n */\n type?: ThreadType;\n\n /**\n * Contacts who can see a private thread.\n * Pass email-based NewContact objects; they are resolved to contact IDs by the API.\n * If omitted for a private thread, defaults to the connection owner.\n */\n accessContacts?: NewContact[];\n\n /**\n * Whether the thread should be marked as unread for users.\n * - undefined/omitted (default): Thread is unread for users, except auto-marked\n * as read for the author if they are the twist owner (user)\n * - true: Thread is explicitly unread for ALL users (use sparingly)\n * - false: Thread is marked as read for all users in the priority at creation time\n */\n unread?: boolean;\n\n /**\n * Whether the thread is archived.\n * - true: Archive the thread\n * - false: Unarchive the thread\n * - undefined (default): Preserve current archive state\n */\n archived?: boolean;\n\n /**\n * Optional preview content for the thread. Can be Markdown formatted.\n * The preview will be automatically generated from this content (truncated to 100 chars).\n */\n preview?: string | null;\n\n /**\n * Optional schedules to create alongside the thread.\n */\n schedules?: Array<Omit<NewSchedule, \"threadId\">>;\n\n /**\n * Optional schedule occurrence overrides.\n */\n scheduleOccurrences?: NewScheduleOccurrence[];\n };\n\nexport type ThreadFilter = {\n meta?: {\n [key: string]: JSONValue;\n };\n};\n\n/**\n * Fields supported by bulk updates via `match`. Only simple scalar fields\n * that can be applied uniformly across many threads are included.\n */\ntype ThreadBulkUpdateFields = Partial<\n Pick<ThreadFields, \"title\" | \"access\" | \"archived\">\n> & {\n /** Contacts who can see a private thread. Pass NewContact objects (email-based); resolved by the API. */\n accessContacts?: NewContact[];\n};\n\n/**\n * Fields supported by single-thread updates via `id` or `source`.\n * Includes all bulk fields plus tags and preview.\n */\ntype ThreadSingleUpdateFields = ThreadBulkUpdateFields & {\n /**\n * Tags to change on the thread. Use an empty array of NewActor to remove a tag.\n * Use twistTags to add/remove the twist from tags to avoid clearing other actors' tags.\n */\n tags?: NewTags;\n\n /**\n * Add or remove the twist's tags.\n * Maps tag ID to boolean: true = add tag, false = remove tag.\n * This is allowed on all threads the twist has access to.\n */\n twistTags?: Partial<Record<Tag, boolean>>;\n\n /**\n * Update the thread's sub-type/category.\n */\n type?: ThreadType;\n\n /**\n * Optional preview content for the thread. Can be Markdown formatted.\n * The preview will be automatically generated from this content (truncated to 100 chars).\n *\n * - string: Use this content for preview generation\n * - null: Explicitly disable preview (no preview will be shown)\n * - undefined (omitted): Preserve current preview value\n *\n * This field is write-only and won't be returned when reading threads.\n */\n preview?: string | null;\n\n /**\n * Move the thread to a different priority. Requires ThreadAccess.Full.\n * The target priority must be owned by the twist's user.\n */\n priority?: Pick<Priority, \"id\">;\n};\n\nexport type ThreadUpdate =\n | (({ id: Uuid } | { source: string }) & ThreadSingleUpdateFields)\n | ({\n /**\n * Update all threads matching the specified criteria. Only threads\n * that match all provided fields and were created by the twist will be updated.\n */\n match: ThreadFilter;\n } & ThreadBulkUpdateFields);\n\n/**\n * Represents a note within a thread.\n *\n * Notes contain the detailed content (note text, actions) associated with a thread.\n * They are always ordered by creation time within their parent thread.\n */\nexport type Note = ThreadCommon & {\n /** The author of this note */\n author: Actor;\n /**\n * Globally unique, stable identifier for the note within its thread + link.\n * Can be used to upsert without knowing the id.\n *\n * Note keys are scoped to a `(thread, link)` pair — two links on the same\n * thread (e.g. after a merge) can each carry a `\"description\"` note without\n * colliding. The runtime infers the link from the surrounding `saveLink`\n * call. For bare `saveNote` calls outside a `saveLink`, the runtime\n * resolves the link by looking up the connector's links on the thread\n * and errors if more than one matches.\n *\n * Use one of these patterns:\n * - Hardcoded semantic keys for fixed note types: \"description\", \"cancellation\"\n * - External service IDs for dynamic collections: `comment:${immutableId}`\n *\n * Examples:\n * - `\"description\"` (for a Jira issue's description note)\n * - `\"comment:12345\"` (for a specific comment by ID)\n * - `\"gmail:msg:18d4e5f2a3b1c9d7\"` (for a Gmail message within a thread)\n *\n * Ensure IDs are immutable - avoid human-readable slugs or titles.\n */\n key: string | null;\n /** The parent thread this note belongs to */\n thread: Thread;\n /** Primary content for the note (markdown) */\n content: string | null;\n /** Array of interactive actions attached to the note */\n actions: Array<Action> | null;\n /** The note this is a reply to, or null if not a reply */\n reNote: { id: Uuid } | null;\n /**\n * Contacts who can see this note, or null if the note inherits thread visibility.\n * When set (even to []), the note is private to the listed contacts plus the creator.\n */\n accessContacts: ActorId[] | null;\n /** Priority twist IDs (twists/connectors) mentioned for dispatch routing. Does not include user contacts. */\n mentions: ActorId[];\n};\n\n/**\n * Type for creating new notes.\n *\n * Requires the thread reference, with all other fields optional.\n * Can provide id, key, or neither for note identification:\n * - id: Provide a specific UUID for the note\n * - key: Provide an external identifier for upsert within the thread\n * - neither: A new note with auto-generated UUID will be created\n */\nexport type NewNote = Partial<\n Omit<\n Note,\n \"author\" | \"thread\" | \"tags\" | \"mentions\" | \"accessContacts\" | \"id\" | \"key\" | \"reNote\"\n >\n> &\n ({ id: Uuid } | { key: string } | {}) & {\n /** Reference to the parent thread (required) */\n thread:\n | Pick<Thread, \"id\">\n | {\n source: string;\n };\n\n /**\n * The person that created the item, or leave undefined to use the twist as author.\n */\n author?: NewActor;\n\n /**\n * Format of the note content. Determines how the note is processed:\n * - 'text': Plain text that will be converted to markdown (auto-links URLs, preserves line breaks)\n * - 'markdown': Already in markdown format (default, no conversion)\n * - 'html': HTML content that will be converted to markdown\n */\n contentType?: ContentType;\n\n /**\n * Tags to change on the thread. Use an empty array of NewActor to remove a tag.\n * Use twistTags to add/remove the twist from tags to avoid clearing other actors' tags.\n */\n tags?: NewTags;\n\n /**\n * Contacts who can see this note, or null/undefined to inherit thread visibility.\n * Accepts resolved ActorId UUIDs or email-based NewContact objects (resolved server-side).\n * Include all participants who should see the note (sender + recipients).\n * The note author is NOT implicitly included — add them explicitly.\n * When set (even to []), the note is private to the listed contacts plus the creator.\n */\n accessContacts?: (ActorId | NewContact)[] | null;\n\n /**\n * Twist/connector IDs to mention for dispatch routing.\n * Does not include user contacts — use accessContacts for visibility.\n */\n mentions?: NewActor[];\n\n /**\n * Whether the note should mark the parent thread as unread for users.\n * - undefined/omitted (default): Thread is unread for users, except auto-marked\n * as read for the author if they are the twist owner (user)\n * - true: Thread is explicitly unread for ALL users (use sparingly)\n * - false: Thread is marked as read for all users in the priority at note creation time\n *\n * For the default behavior, omit this field entirely.\n * Use false for initial sync to avoid marking historical items as unread.\n */\n unread?: boolean;\n\n /**\n * When true, the server will use AI to detect tasks in this note's content\n * and create separate Plot-authored reply notes for each detected task.\n * Use for messaging connectors (email, chat) where tasks are implicit\n * in conversation rather than explicitly structured.\n */\n checkForTasks?: boolean;\n\n /**\n * Reference to a parent note this note is a reply to.\n * - `{ id }`: reply by UUID\n * - `{ key }`: reply by key, resolved after creation (for batch ops)\n * - `null`: explicitly not a reply\n * - `undefined` (omitted): not a reply\n */\n reNote?: { id: Uuid } | { key: string } | null;\n };\n\n/**\n * Type for updating existing notes.\n * Must provide either id or key to identify the note to update.\n */\nexport type NoteUpdate = ({ id: Uuid; key?: string } | { key: string }) &\n Partial<\n Pick<Note, \"accessContacts\" | \"archived\" | \"content\" | \"actions\" | \"reNote\">\n > & {\n /**\n * Format of the note content. Determines how the note is processed:\n * - 'text': Plain text that will be converted to markdown (auto-links URLs, preserves line breaks)\n * - 'markdown': Already in markdown format (default, no conversion)\n * - 'html': HTML content that will be converted to markdown\n */\n contentType?: ContentType;\n\n /**\n * Tags to change on the note. Use an empty array of NewActor to remove a tag.\n * Use twistTags to add/remove the twist from tags to avoid clearing other actors' tags.\n */\n tags?: NewTags;\n\n /**\n * Add or remove the twist's tags.\n * Maps tag ID to boolean: true = add tag, false = remove tag.\n * This is allowed on all notes the twist has access to.\n */\n twistTags?: Partial<Record<Tag, boolean>>;\n\n /**\n * Twist/connector IDs to mention for dispatch routing.\n * Does not include user contacts — use accessContacts for visibility.\n */\n mentions?: NewActor[];\n };\n\n/**\n * Represents an actor in Plot - a user, contact, or twist.\n *\n * Actors can be associated with threads as authors, assignees, or mentions.\n * The email field is only included when ContactAccess.Read permission is granted.\n *\n * @example\n * ```typescript\n * const actor: Actor = {\n * id: \"f0ffd5f8-1635-4b13-9532-35f97446db90\" as ActorId,\n * type: ActorType.Contact,\n * email: \"john.doe@example.com\", // Only if ContactAccess.Read\n * name: \"John Doe\"\n * };\n * ```\n */\nexport type Actor = {\n /** Unique identifier for the actor */\n id: ActorId;\n /** Type of actor (User, Contact, or Twist) */\n type: ActorType;\n /**\n * Email address (only included with ContactAccess.Read permission).\n * - `undefined`: No permission to read email\n * - `null`: Permission granted but email not set\n * - `string`: Email address\n */\n email?: string | null;\n /**\n * Display name.\n * - `undefined`: Not included due to permissions\n * - `null`: Not set\n * - `string`: Display name\n */\n name?: string | null;\n};\n\n/**\n * A resolved contact with identity info. Used for access control lists\n * where only human contacts (not twists) are relevant.\n */\nexport type Contact = {\n /** Unique identifier for the contact */\n id: ActorId;\n /** Email address, or null if not set */\n email: string | null;\n /** Display name, or null if not set */\n name: string | null;\n};\n\n/**\n * An existing or new contact.\n */\nexport type NewActor =\n | {\n /** Unique identifier for the actor */\n id: ActorId;\n }\n | NewContact;\n\n/**\n * Enumeration of author types that can create threads.\n *\n * The author type affects how threads are displayed and processed\n * within the Plot system.\n */\nexport enum ActorType {\n /** Threads created by human users */\n User,\n /** Threads created by external contacts */\n Contact,\n /** Threads created by automated twists */\n Twist,\n}\n\n/**\n * Represents contact information for creating a new contact.\n *\n * Contacts are used throughout Plot for representing people associated\n * with activities, such as event attendees or task assignees.\n *\n * @example\n * ```typescript\n * const newContact: NewContact = {\n * email: \"john.doe@example.com\",\n * name: \"John Doe\",\n * avatar: \"https://avatar.example.com/john.jpg\"\n * };\n * ```\n */\n/**\n * Common fields shared by all NewContact variants.\n */\ntype NewContactBase = {\n /** Optional avatar image URL for the contact */\n avatar?: string;\n /**\n * External provider account source. Used for identity resolution\n * when email is unavailable and for privacy compliance reporting.\n */\n source?: { provider: AuthProvider; accountId: string };\n};\n\n/**\n * At least one of `email` or `name` must be provided so the contact can be\n * identified in the UI. Contacts with neither would display as \"Unknown\".\n */\nexport type NewContact = NewContactBase &\n ({ email: string; name?: string } | { email?: string; name: string });\n\nexport type ContentType = \"text\" | \"markdown\" | \"html\";\n\n/**\n * Represents an external entity linked to a thread.\n *\n * Links are created by sources to represent external entities (issues, emails, calendar events)\n * attached to a thread container. A thread can have multiple links (1:many).\n * Links store source-specific data like type, status, metadata, and embeddings.\n *\n * @example\n * ```typescript\n * // A link representing a Linear issue\n * const link: Link = {\n * threadId: \"...\" as Uuid,\n * source: \"linear:issue:549dd8bd-2bc9-43d1-95d5-4b4af0c5af1b\",\n * created: new Date(),\n * author: { id: \"...\" as ActorId, type: ActorType.Contact, name: \"Alice\" },\n * title: \"Fix login bug\",\n * type: \"issue\",\n * status: \"open\",\n * meta: { projectId: \"TEAM\", url: \"https://linear.app/team/TEAM-123\" },\n * assignee: null,\n * actions: null,\n * };\n * ```\n */\nexport type Link = {\n /** The thread this link belongs to */\n threadId: Uuid;\n /** External source identifier for dedup/upsert */\n source: string | null;\n /** When this link was originally created in its source system */\n created: Date;\n /** The actor credited with creating this link */\n author: Actor | null;\n /** Display title */\n title: string;\n /** Truncated preview */\n preview: string | null;\n /** The actor assigned to this link */\n assignee: Actor | null;\n /** Source-defined type string (e.g., issue, pull_request, email, event) */\n type: string | null;\n /** Source-defined status string (e.g., open, done, closed) */\n status: string | null;\n /** Interactive action buttons */\n actions: Array<Action> | null;\n /** Source metadata */\n meta: ThreadMeta | null;\n /** URL to open the original item in its source application (e.g., \"Open in Linear\") */\n sourceUrl: string | null;\n /** Channel ID that produced this link (matches source_channel.channel_id) */\n channelId: string | null;\n /**\n * Cross-connector thread bundling key.\n *\n * @deprecated Use `sources` instead. Reads return the first element of\n * `sources` for backward compatibility; new writes should populate `sources`.\n */\n relatedSource: string | null;\n /**\n * Canonical identifiers for this link. Two links whose `sources` arrays\n * overlap share the same thread (array overlap, `sources && new.sources`).\n *\n * Use this to bundle with another connector via a canonical alias. For\n * example, every calendar connector emits `icaluid:<iCalUID>` so any\n * meeting-notes connector can bundle by setting the same alias.\n */\n sources: string[];\n};\n\n/**\n * Type for creating new links.\n *\n * Links are created by sources to represent external entities.\n * Requires a source identifier for dedup/upsert.\n */\nexport type NewLink = Partial<\n Omit<Link, \"author\" | \"assignee\" | \"threadId\">\n> & {\n /**\n * Canonical ID for the item in an external system.\n * When set, uniquely identifies the link within a priority tree. This performs\n * an upsert.\n *\n * @deprecated Pass `sources: [...]` instead. Both fields can be set during\n * the transition; the runtime will normalize.\n */\n source?: string;\n /**\n * Canonical identifiers for this item. Any element shared with another\n * link's `sources` bundles the two links into the same thread. Used for\n * cross-connector bundling — e.g. a meeting-notes connector setting\n * `[\"granola:<id>\", \"icaluid:<uid>\"]` to attach onto a calendar event\n * thread that includes `icaluid:<uid>` in its own `sources`.\n */\n sources?: string[];\n /** The person that created the item. By default, it will be the twist itself. */\n author?: NewActor;\n /** The person assigned to the item. */\n assignee?: NewActor | null;\n /**\n * Thread access level: \"public\", \"members\" (default), or \"private\".\n * When \"private\", thread visibility is limited to the creator and contacts in accessContacts.\n */\n access?: ThreadAccessLevel;\n /**\n * Contacts who can see a private thread.\n * Pass email-based NewContact objects; they are resolved to contact IDs by the API.\n * If omitted for a private thread, defaults to the connection owner.\n */\n accessContacts?: NewContact[];\n /**\n * Whether the thread should be marked as unread for users.\n * - undefined/omitted (default): Thread is unread for users, except auto-marked\n * as read for the author if they are the twist owner (user)\n * - false: Thread is marked as read for all users in the priority at creation time\n */\n unread?: boolean;\n /**\n * Whether the thread is archived.\n * - true: Archive the thread\n * - false: Unarchive the thread\n * - undefined (default): Preserve current archive state\n */\n archived?: boolean;\n /**\n * Explicit priority (disables automatic priority matching).\n * Only used when the link creates a new thread. When omitted, the\n * server classifies the thread using the user's priority rules.\n */\n priority?: Pick<Priority, \"id\">;\n };\n\n/**\n * A new link with notes to save via integrations.saveLink().\n * Creates a thread+link pair, with notes attached to the thread.\n */\nexport type NewLinkWithNotes = NewLink & {\n /**\n * Title for the link and its thread container.\n * Must be the real entity title (e.g. issue title, message subject),\n * never a placeholder or ID. This value overwrites the existing title on upsert.\n * Omit to preserve the existing title (e.g. for cancelled events where the\n * title may not be available in the webhook payload).\n */\n title?: string;\n /** Notes to attach to the thread */\n notes?: Omit<NewNote, \"thread\">[];\n /** Schedules to create for the link */\n schedules?: Array<Omit<NewSchedule, \"threadId\">>;\n /** Schedule occurrence overrides */\n scheduleOccurrences?: NewScheduleOccurrence[];\n};\n\n/**\n * Type for updating existing links.\n *\n * Set `threadId` to move the link to a different thread.\n * Requires LinkAccess.Full.\n */\nexport type LinkUpdate = { id: Uuid } & {\n /** Move the link to a different thread owned by the twist's user. */\n threadId?: Uuid;\n};\n\n/**\n * A single operation within a plan submitted for user approval.\n *\n * Operations include display metadata (titles) so the app can render\n * a human-readable summary without additional lookups.\n */\nexport type PlanOperation =\n | {\n type: \"updateThread\";\n threadId: Uuid;\n /** Current thread title for display */\n threadTitle: string;\n changes: Partial<Pick<ThreadFields, \"archived\" | \"title\" | \"type\">> & {\n /** Move to this priority */\n priority?: { id: Uuid; title: string };\n };\n }\n | {\n type: \"updateLink\";\n linkId: Uuid;\n /** Current link title for display */\n linkTitle: string;\n changes: {\n /** Move to this thread */\n threadId?: Uuid;\n threadTitle?: string;\n };\n }\n | {\n type: \"createThread\";\n title: string;\n priorityId: Uuid;\n /** Priority title for display */\n priorityTitle: string;\n }\n | {\n type: \"createNote\";\n threadId: Uuid;\n /** Thread title for display */\n threadTitle: string;\n content: string;\n }\n | {\n type: \"updatePriority\";\n priorityId: Uuid;\n /** Current priority title for display */\n priorityTitle: string;\n changes: Partial<Pick<Priority, \"title\" | \"archived\">> & {\n /** Move under this parent */\n parent?: { id: Uuid; title: string };\n };\n };\n";
7
+ export default "import type { NewSchedule, NewScheduleOccurrence, Schedule } from \"./schedule\";\nimport { type Tag } from \"./tag\";\nimport { type Callback } from \"./tools/callbacks\";\nimport { type JSONValue } from \"./utils/types\";\nimport { Uuid } from \"./utils/uuid\";\n\nexport { Tag } from \"./tag\";\nexport { Uuid } from \"./utils/uuid\";\nexport { type JSONValue } from \"./utils/types\";\nexport { type AuthProvider } from \"./tools/integrations\";\n\n/**\n * @fileoverview\n * Core Plot entity types for working with threads, notes, focuses, and contacts.\n *\n * ## Type Pattern: Null vs Undefined Semantics\n *\n * Plot entity types use a consistent pattern to distinguish between missing, unset, and explicitly cleared values:\n *\n * ### Entity Types (Thread, Focus, Note, Actor)\n * - **Required fields**: No `?`, cannot be `undefined`\n * - Example: `id: Uuid`, `title: string`\n * - **Nullable fields**: Use `| null` to allow explicit clearing\n * - Example: `assignee: ActorId | null`, `done: Date | null`\n * - `null` = field is explicitly unset/cleared\n * - Non-null value = field has a value\n * - **Optional nullable fields**: Use `?` with `| null` for permission-based access\n * - Example: `email?: string | null`, `name?: string | null`\n * - `undefined` = field not included (e.g., no permission to access)\n * - `null` = field included but not set\n * - Value = field has a value\n *\n * ### New* Types (NewThread, NewNote, NewFocus)\n * Used for creating or updating entities. Support partial updates by distinguishing omitted vs cleared fields:\n * - **Required fields**: Must be provided (no `?`)\n * - Example: `title: string` in NewFocus\n * - **Optional fields**: Use `?` to make them optional\n * - Example: `title?: string`, `author?: NewActor`\n * - `undefined` (omitted) = don't set/update this field\n * - Provided value = set/update this field\n * - **Optional nullable fields**: Use `?` with `| null` to support clearing\n * - Example: `assignee?: NewActor | null`\n * - `undefined` (omitted) = don't change assignee\n * - `null` = clear the assignee\n * - NewActor = set/update the assignee\n *\n * This pattern allows API consumers to:\n * 1. Omit fields they don't want to change (undefined)\n * 2. Explicitly clear fields by setting to null\n * 3. Set or update fields by providing values\n *\n * @example\n * ```typescript\n * // Creating a new thread\n * const newThread: NewThread = {\n * title: \"Review pull request\",\n * };\n *\n * // Updating a thread - only change what's specified\n * const update: ThreadUpdate = {\n * id: threadId,\n * archived: true,\n * };\n * ```\n */\n\n/**\n * Represents a unique user, contact, or twist in Plot.\n *\n * ActorIds are used throughout Plot for:\n * - Activity authors and assignees\n * - Tag creators (actor_id in activity_tag/note_tag)\n * - Mentions in activities and notes\n * - Any entity that can perform actions in Plot\n */\nexport type ActorId = string & { readonly __brand: \"ActorId\" };\n\n/**\n * Theme colors for focuses.\n */\nexport enum ThemeColor {\n /** Catalyst - Green */\n Catalyst = 0,\n /** Call to Adventure - Blue */\n CallToAdventure = 1,\n /** Rising Action - Purple */\n RisingAction = 2,\n /** Momentum - Pink-Purple */\n Momentum = 3,\n /** Turning Point - Pink */\n TurningPoint = 4,\n /** Breakthrough - Orange */\n Breakthrough = 5,\n /** Climax - Olive */\n Climax = 6,\n /** Resolution - Blue-Gray */\n Resolution = 7,\n}\n\n/**\n * Represents a focus within Plot.\n *\n * A focus is similar to a project or area-of-life. All Activity is in a Focus.\n * Focuses are flat — they have no parent and no children. Threads not matched\n * to any focus live in the Inbox.\n */\nexport type Focus = {\n /** Unique identifier for the focus */\n id: Uuid;\n /** Human-readable title for the focus */\n title: string;\n /** Whether this focus has been archived */\n archived: boolean;\n /**\n * Optional key for referencing this focus.\n * Keys are unique per user.\n */\n key: string | null;\n /** Optional theme color for the focus (0-7). Defaults to 7 (Resolution) when not set. */\n color: ThemeColor | null;\n /** Optional icon for the focus (a curated icon key). Defaults to the focus icon when not set. */\n icon: string | null;\n};\n\n/**\n * Type for creating new focuses.\n *\n * Supports multiple creation patterns:\n * - Provide a specific UUID for the focus\n * - Provide a key for upsert within the user's focuses\n * - Omit both to auto-generate a new UUID\n */\nexport type NewFocus = Pick<Focus, \"title\"> &\n Partial<Omit<Focus, \"id\" | \"title\">> &\n (\n | {\n /**\n * Unique identifier for the focus, generated by Uuid.Generate().\n * Specifying an ID allows tools to track and upsert focuses.\n */\n id: Uuid;\n }\n | {\n /**\n * Unique key for the focus within the user's focuses.\n * Can be used to upsert without knowing the UUID.\n * For example, \"@plot\" identifies the Plot focus.\n */\n key: string;\n }\n | {\n /* Neither id nor key is required. An id will be generated and returned. */\n }\n );\n\n/**\n * Type for updating existing focuses.\n * Must provide either id or key to identify the focus to update.\n */\nexport type FocusUpdate = ({ id: Uuid } | { key: string }) &\n Partial<Pick<Focus, \"title\" | \"archived\">>;\n\n/**\n * Enumeration of supported action types.\n *\n * Different action types have different behaviors when clicked by users\n * and may require different rendering approaches.\n */\nexport enum ActionType {\n /** External web links that open in browser */\n external = \"external\",\n /** Authentication flows for connecting services */\n auth = \"auth\",\n /** Callback actions that trigger twist methods when clicked */\n callback = \"callback\",\n /** Video conferencing links with provider-specific handling */\n conferencing = \"conferencing\",\n /** File attachment links stored in R2 */\n file = \"file\",\n /** Reference to an attachment hosted by a connector's source system */\n fileRef = \"fileRef\",\n /** Thread reference links for navigating to related threads */\n thread = \"thread\",\n /** Structured plan of operations for user approval */\n plan = \"plan\",\n}\n\n/**\n * Video conferencing providers for conferencing links.\n *\n * Used to identify the conferencing platform and provide\n * provider-specific UI elements (titles, icons, etc.).\n */\nexport enum ConferencingProvider {\n /** Google Meet */\n googleMeet = \"googleMeet\",\n /** Zoom */\n zoom = \"zoom\",\n /** Microsoft Teams */\n microsoftTeams = \"microsoftTeams\",\n /** Cisco Webex */\n webex = \"webex\",\n /** Other or unknown conferencing provider */\n other = \"other\",\n}\n\n/**\n * Represents a clickable action attached to a thread.\n *\n * Thread actions are rendered as buttons that enable user interaction with threads.\n * Different action types have specific behaviors and required fields for proper functionality.\n *\n * @example\n * ```typescript\n * // External action - opens URL in browser\n * const externalAction: Action = {\n * type: ActionType.external,\n * title: \"Open in Google Calendar\",\n * url: \"https://calendar.google.com/event/123\",\n * };\n *\n * // Conferencing action - opens video conference with provider info\n * const conferencingAction: Action = {\n * type: ActionType.conferencing,\n * url: \"https://meet.google.com/abc-defg-hij\",\n * provider: ConferencingProvider.googleMeet,\n * };\n *\n * // Integrations action - initiates OAuth flow\n * const authAction: Action = {\n * type: ActionType.auth,\n * title: \"Continue with Google\",\n * provider: AuthProvider.Google,\n * scopes: [\"https://www.googleapis.com/auth/calendar.readonly\"],\n * callback: \"callback-token-for-auth-completion\"\n * };\n *\n * // Callback action - triggers a twist method\n * const callbackAction: Action = {\n * type: ActionType.callback,\n * title: \"📅 Primary Calendar\",\n * token: \"callback-token-here\"\n * };\n * ```\n */\nexport type Action =\n | {\n /** External web link that opens in browser */\n type: ActionType.external;\n /** Display text for the action button */\n title: string;\n /** URL to open when clicked */\n url: string;\n }\n | {\n /** Video conferencing action with provider-specific handling */\n type: ActionType.conferencing;\n /** URL to join the conference */\n url: string;\n /** Conferencing provider for UI customization */\n provider: ConferencingProvider;\n }\n | {\n /** Authentication action that initiates an OAuth flow */\n type: ActionType.auth;\n /** Display text for the auth button */\n title: string;\n /** OAuth provider (e.g., \"google\", \"microsoft\") */\n provider: string;\n /** Array of OAuth scopes to request */\n scopes: string[];\n /** Callback token for auth completion notification */\n callback: Callback;\n }\n | {\n /** Callback action that triggers a twist method when clicked */\n type: ActionType.callback;\n /** Display text for the callback button */\n title: string;\n /** Token identifying the callback to execute */\n callback: Callback;\n }\n | {\n /** File attachment action stored in R2 */\n type: ActionType.file;\n /** Unique identifier for the stored file */\n fileId: string;\n /** Original filename */\n fileName: string;\n /** File size in bytes */\n fileSize: number;\n /** MIME type of the file */\n mimeType: string;\n /** Intrinsic width of the image in pixels (only for image files) */\n imageWidth?: number | null;\n /** Intrinsic height of the image in pixels (only for image files) */\n imageHeight?: number | null;\n }\n | {\n /** Reference to an attachment hosted by a connector's source system */\n type: ActionType.fileRef;\n /** Opaque identifier interpreted only by the owning connector */\n ref: string;\n /** Display filename */\n fileName: string;\n /** File size in bytes if known */\n fileSize: number | null;\n /** MIME type */\n mimeType: string;\n /** Intrinsic width of the image in pixels (only for image files) */\n imageWidth?: number | null;\n /** Intrinsic height of the image in pixels (only for image files) */\n imageHeight?: number | null;\n }\n | {\n /** Thread reference action for navigating to a related thread */\n type: ActionType.thread;\n /** UUID of the referenced thread */\n threadId: Uuid;\n }\n | {\n /** Structured plan of operations for user approval */\n type: ActionType.plan;\n /** Human-readable summary of the plan */\n title: string;\n /** Operations to execute on approval */\n operations: PlanOperation[];\n /** Callback invoked with (action, approved: boolean) */\n callback: Callback;\n };\n\n/**\n * Represents metadata about a thread, typically from an external system.\n *\n * Thread metadata enables storing additional information about threads,\n * which is useful for synchronization, linking back to external systems,\n * and storing tool-specific data.\n *\n * Must be valid JSON data (strings, numbers, booleans, null, objects, arrays).\n * Functions and other non-JSON values are not supported.\n *\n * @example\n * ```typescript\n * // Calendar event metadata\n * await plot.createThread({\n * title: \"Team Meeting\",\n * meta: {\n * calendarId: \"primary\",\n * htmlLink: \"https://calendar.google.com/event/abc123\",\n * conferenceData: { ... }\n * }\n * });\n *\n * // Project issue metadata\n * await plot.createThread({\n * title: \"Fix login bug\",\n * meta: {\n * projectId: \"TEAM\",\n * issueNumber: 123,\n * url: \"https://linear.app/team/issue/TEAM-123\"\n * }\n * });\n * ```\n */\nexport type ThreadMeta = {\n /** Source-specific properties and metadata */\n [key: string]: JSONValue;\n};\n\n/**\n * Thread sub-type that determines the thread's icon and category.\n * Available types depend on whether the focus is shared:\n * - Private focuses: \"action\" (default for tasks), \"notes\" (default), \"idea\", \"goal\", \"decision\"\n * - Shared focuses: all above plus \"discussion\" (default), \"announcement\", \"ask\"\n */\nexport type ThreadType =\n | \"action\"\n | \"notes\"\n | \"idea\"\n | \"goal\"\n | \"decision\"\n | \"discussion\"\n | \"announcement\"\n | \"ask\";\n\n/**\n * Tags on an item, along with the actors who added each tag.\n */\nexport type Tags = { [K in Tag]?: ActorId[] };\n\n/**\n * A set of tags to add to an item, along with the actors adding each tag.\n */\nexport type NewTags = { [K in Tag]?: NewActor[] };\n\n/**\n * A single emoji reaction key. Either:\n * - A Unicode emoji grapheme cluster (e.g. `\"👍\"`, `\"👨‍👩‍👧\"`), or\n * - A provider-scoped custom-emoji ref of the form\n * `\"<provider>:<workspaceId>/<name>\"` (e.g. `\"slack:T0123/party_parrot\"`).\n *\n * Anything matching a known provider prefix is treated as a custom-emoji\n * reference; everything else is rendered as the Unicode it contains.\n *\n * Reactions are the open-set counterpart to {@link Tag}'s count range\n * (`1000+`). Use reactions for emoji that round-trip with chat platforms;\n * use tags for Plot-managed compute/toggle state (todo, pinned, urgent,\n * ...).\n */\nexport type Reaction = string;\n\n/**\n * Emoji reactions on an item, keyed by emoji string, with the list of\n * actors who added each reaction.\n */\nexport type Reactions = Record<Reaction, ActorId[]>;\n\n/**\n * A set of reactions to add to an item, along with the actors adding each\n * reaction. To remove a reaction for a given actor, omit them from the\n * `NewActor[]` list — passing an empty list removes the reaction entirely.\n */\nexport type NewReactions = Record<Reaction, NewActor[]>;\n\n/**\n * Thread access level determining visibility.\n * - \"public\": Visible to all users with focus access\n * - \"members\": Visible to focus members (default for shared focuses)\n * - \"private\": Visible only to creator and contacts listed in accessContacts\n */\nexport type ThreadAccessLevel = \"public\" | \"members\" | \"private\";\n\n/**\n * Common fields shared by both Thread and Note entities.\n */\nexport type ThreadCommon = {\n /** Unique identifier for the thread */\n id: Uuid;\n /**\n * When this item was created.\n *\n * **For sources:** Set this to the external system's timestamp (e.g., email\n * sent date, comment creation date), NOT the sync time. If omitted, defaults\n * to the current time, which is almost never correct for synced data.\n */\n created: Date;\n /** Whether this thread has been archived */\n archived: boolean;\n /** Tags attached to this thread. Maps tag ID to array of actor IDs who added that tag. */\n tags: Tags;\n /**\n * Emoji reactions on this item. Maps each emoji (Unicode grapheme or\n * `provider:workspace/name` custom-emoji ref) to the list of actor IDs\n * who reacted with it.\n */\n reactions: Reactions;\n};\n\n/**\n * Fields on a Thread entity.\n * Threads are simple containers for links and notes.\n */\ntype ThreadFields = ThreadCommon & {\n /** The display title/summary of the thread */\n title: string;\n /** The focus context this thread belongs to */\n focus: Focus;\n /** The thread's sub-type/category. Determines the displayed icon. */\n type: ThreadType | null;\n /** Thread access level: \"public\", \"members\", or \"private\" */\n access: ThreadAccessLevel;\n /** Contacts who can see a private thread (empty array for creator-only). Only meaningful when access is \"private\". */\n accessContacts: Contact[];\n /** The schedule associated with this thread, if any */\n schedule?: Schedule;\n /** Source-specific metadata from the thread's link, populated on callbacks */\n meta?: ThreadMeta;\n};\n\nexport type Thread = ThreadFields;\n\nexport type ThreadWithNotes = Thread & {\n notes: Note[];\n};\n\nexport type NewThreadWithNotes = NewThread & {\n notes: Omit<NewNote, \"thread\">[];\n};\n\n/**\n * Type for creating new threads.\n *\n * Threads are simple containers. All other fields are optional.\n *\n * @example\n * ```typescript\n * const thread: NewThread = {\n * title: \"Review pull request\"\n * };\n * ```\n */\nexport type NewThread = Partial<\n Omit<ThreadFields, \"focus\" | \"tags\" | \"reactions\" | \"id\" | \"accessContacts\">\n> &\n (\n | {\n /** Unique identifier for the thread, generated by Uuid.Generate(). */\n id: Uuid;\n }\n | {\n /* id is optional. An id will be generated and returned. */\n }\n ) &\n {\n /** Explicit focus - disables automatic focus matching. When omitted, the server classifies the thread using the user's focus rules. */\n focus?: Pick<Focus, \"id\">;\n } & {\n /**\n * All tags to set on the new thread.\n */\n tags?: NewTags;\n\n /**\n * Emoji reactions to set on the new thread.\n * Each emoji maps to the list of actors who reacted with it.\n */\n reactions?: NewReactions;\n\n /**\n * The thread's sub-type/category. Sets the thread's icon.\n * If omitted, defaults to \"notes\" (private) or \"discussion\" (shared).\n */\n type?: ThreadType;\n\n /**\n * Contacts who can see a private thread.\n * Pass email-based NewContact objects; they are resolved to contact IDs by the API.\n * If omitted for a private thread, defaults to the connection owner.\n */\n accessContacts?: NewContact[];\n\n /**\n * Whether the thread should be marked as unread for users.\n * - undefined/omitted (default): Thread is unread for users, except auto-marked\n * as read for the author if they are the twist owner (user)\n * - true: Thread is explicitly unread for ALL users (use sparingly)\n * - false: Thread is marked as read for all users in the focus at creation time\n */\n unread?: boolean;\n\n /**\n * Whether the thread is archived.\n * - true: Archive the thread\n * - false: Unarchive the thread\n * - undefined (default): Preserve current archive state\n */\n archived?: boolean;\n\n /**\n * Optional preview content for the thread. Can be Markdown formatted.\n * The preview will be automatically generated from this content (truncated to 100 chars).\n */\n preview?: string | null;\n\n /**\n * Optional schedules to create alongside the thread.\n */\n schedules?: Array<Omit<NewSchedule, \"threadId\">>;\n\n /**\n * Optional schedule occurrence overrides.\n */\n scheduleOccurrences?: NewScheduleOccurrence[];\n };\n\nexport type ThreadFilter = {\n meta?: {\n [key: string]: JSONValue;\n };\n};\n\n/**\n * Fields supported by bulk updates via `match`. Only simple scalar fields\n * that can be applied uniformly across many threads are included.\n */\ntype ThreadBulkUpdateFields = Partial<\n Pick<ThreadFields, \"title\" | \"access\" | \"archived\">\n> & {\n /** Contacts who can see a private thread. Pass NewContact objects (email-based); resolved by the API. */\n accessContacts?: NewContact[];\n};\n\n/**\n * Fields supported by single-thread updates via `id` or `source`.\n * Includes all bulk fields plus tags and preview.\n */\ntype ThreadSingleUpdateFields = ThreadBulkUpdateFields & {\n /**\n * Tags to change on the thread. Use an empty array of NewActor to remove a tag.\n * Use twistTags to add/remove the twist from tags to avoid clearing other actors' tags.\n */\n tags?: NewTags;\n\n /**\n * Emoji reactions to change on the thread. Pass an empty `NewActor[]` to\n * remove a reaction entirely; omit an emoji to leave it untouched.\n */\n reactions?: NewReactions;\n\n /**\n * Add or remove the twist's tags.\n * Maps tag ID to boolean: true = add tag, false = remove tag.\n * This is allowed on all threads the twist has access to.\n */\n twistTags?: Partial<Record<Tag, boolean>>;\n\n /**\n * Update the thread's sub-type/category.\n */\n type?: ThreadType;\n\n /**\n * Optional preview content for the thread. Can be Markdown formatted.\n * The preview will be automatically generated from this content (truncated to 100 chars).\n *\n * - string: Use this content for preview generation\n * - null: Explicitly disable preview (no preview will be shown)\n * - undefined (omitted): Preserve current preview value\n *\n * This field is write-only and won't be returned when reading threads.\n */\n preview?: string | null;\n\n /**\n * Move the thread to a different focus. Requires ThreadAccess.Full.\n * The target focus must be owned by the twist's user.\n */\n focus?: Pick<Focus, \"id\">;\n};\n\nexport type ThreadUpdate =\n | (({ id: Uuid } | { source: string }) & ThreadSingleUpdateFields)\n | ({\n /**\n * Update all threads matching the specified criteria. Only threads\n * that match all provided fields and were created by the twist will be updated.\n */\n match: ThreadFilter;\n } & ThreadBulkUpdateFields);\n\n/**\n * Represents a note within a thread.\n *\n * Notes contain the detailed content (note text, actions) associated with a thread.\n * They are always ordered by creation time within their parent thread.\n */\nexport type Note = ThreadCommon & {\n /** The author of this note */\n author: Actor;\n /**\n * Globally unique, stable identifier for the note within its thread + link.\n * Can be used to upsert without knowing the id.\n *\n * Note keys are scoped to a `(thread, link)` pair — two links on the same\n * thread (e.g. after a merge) can each carry a `\"description\"` note without\n * colliding. The runtime infers the link from the surrounding `saveLink`\n * call. For bare `saveNote` calls outside a `saveLink`, the runtime\n * resolves the link by looking up the connector's links on the thread\n * and errors if more than one matches.\n *\n * Use one of these patterns:\n * - Hardcoded semantic keys for fixed note types: \"description\", \"cancellation\"\n * - External service IDs for dynamic collections: `comment:${immutableId}`\n *\n * Examples:\n * - `\"description\"` (for a Jira issue's description note)\n * - `\"comment:12345\"` (for a specific comment by ID)\n * - `\"gmail:msg:18d4e5f2a3b1c9d7\"` (for a Gmail message within a thread)\n *\n * Ensure IDs are immutable - avoid human-readable slugs or titles.\n */\n key: string | null;\n /** The parent thread this note belongs to */\n thread: Thread;\n /** Primary content for the note (markdown) */\n content: string | null;\n /** Array of interactive actions attached to the note */\n actions: Array<Action> | null;\n /** The note this is a reply to, or null if not a reply */\n reNote: { id: Uuid } | null;\n /**\n * Contacts who can see this note, or null if the note inherits thread visibility.\n * When set (even to []), the note is private to the listed contacts plus the creator.\n */\n accessContacts: ActorId[] | null;\n /** Focus twist IDs (twists/connectors) mentioned for dispatch routing. Does not include user contacts. */\n mentions: ActorId[];\n};\n\n/**\n * Type for creating new notes.\n *\n * Requires the thread reference, with all other fields optional.\n * Can provide id, key, or neither for note identification:\n * - id: Provide a specific UUID for the note\n * - key: Provide an external identifier for upsert within the thread\n * - neither: A new note with auto-generated UUID will be created\n */\nexport type NewNote = Partial<\n Omit<\n Note,\n \"author\" | \"thread\" | \"tags\" | \"reactions\" | \"mentions\" | \"accessContacts\" | \"id\" | \"key\" | \"reNote\"\n >\n> &\n ({ id: Uuid } | { key: string } | {}) & {\n /** Reference to the parent thread (required) */\n thread:\n | Pick<Thread, \"id\">\n | {\n source: string;\n };\n\n /**\n * The person that created the item, or leave undefined to use the twist as author.\n */\n author?: NewActor;\n\n /**\n * Format of the note content. Determines how the note is processed:\n * - 'text': Plain text that will be converted to markdown (auto-links URLs, preserves line breaks)\n * - 'markdown': Already in markdown format (default, no conversion)\n * - 'html': HTML content that will be converted to markdown\n */\n contentType?: ContentType;\n\n /**\n * Tags to change on the thread. Use an empty array of NewActor to remove a tag.\n * Use twistTags to add/remove the twist from tags to avoid clearing other actors' tags.\n */\n tags?: NewTags;\n\n /**\n * Emoji reactions to set on the note. Pass an empty `NewActor[]` to\n * remove a reaction entirely; omit an emoji to leave it untouched.\n */\n reactions?: NewReactions;\n\n /**\n * Contacts who can see this note, or null/undefined to inherit thread visibility.\n * Accepts resolved ActorId UUIDs or email-based NewContact objects (resolved server-side).\n * Include all participants who should see the note (sender + recipients).\n * The note author is NOT implicitly included — add them explicitly.\n * When set (even to []), the note is private to the listed contacts plus the creator.\n */\n accessContacts?: (ActorId | NewContact)[] | null;\n\n /**\n * Twist/connector IDs to mention for dispatch routing.\n * Does not include user contacts — use accessContacts for visibility.\n */\n mentions?: NewActor[];\n\n /**\n * Whether the note should mark the parent thread as unread for users.\n * - undefined/omitted (default): Thread is unread for users, except auto-marked\n * as read for the author if they are the twist owner (user)\n * - true: Thread is explicitly unread for ALL users (use sparingly)\n * - false: Thread is marked as read for all users in the focus at note creation time\n *\n * For the default behavior, omit this field entirely.\n * Use false for initial sync to avoid marking historical items as unread.\n */\n unread?: boolean;\n\n /**\n * When true, the server will use AI to detect tasks in this note's content\n * and create separate Plot-authored reply notes for each detected task.\n * Use for messaging connectors (email, chat) where tasks are implicit\n * in conversation rather than explicitly structured.\n */\n checkForTasks?: boolean;\n\n /**\n * Reference to a parent note this note is a reply to.\n * - `{ id }`: reply by UUID\n * - `{ key }`: reply by key, resolved after creation (for batch ops)\n * - `null`: explicitly not a reply\n * - `undefined` (omitted): not a reply\n */\n reNote?: { id: Uuid } | { key: string } | null;\n };\n\n/**\n * Type for updating existing notes.\n * Must provide either id or key to identify the note to update.\n */\nexport type NoteUpdate = ({ id: Uuid; key?: string } | { key: string }) &\n Partial<\n Pick<Note, \"accessContacts\" | \"archived\" | \"content\" | \"actions\" | \"reNote\">\n > & {\n /**\n * Format of the note content. Determines how the note is processed:\n * - 'text': Plain text that will be converted to markdown (auto-links URLs, preserves line breaks)\n * - 'markdown': Already in markdown format (default, no conversion)\n * - 'html': HTML content that will be converted to markdown\n */\n contentType?: ContentType;\n\n /**\n * Tags to change on the note. Use an empty array of NewActor to remove a tag.\n * Use twistTags to add/remove the twist from tags to avoid clearing other actors' tags.\n */\n tags?: NewTags;\n\n /**\n * Emoji reactions to change on the note. Pass an empty `NewActor[]` to\n * remove a reaction entirely; omit an emoji to leave it untouched.\n */\n reactions?: NewReactions;\n\n /**\n * Add or remove the twist's tags.\n * Maps tag ID to boolean: true = add tag, false = remove tag.\n * This is allowed on all notes the twist has access to.\n */\n twistTags?: Partial<Record<Tag, boolean>>;\n\n /**\n * Twist/connector IDs to mention for dispatch routing.\n * Does not include user contacts — use accessContacts for visibility.\n */\n mentions?: NewActor[];\n };\n\n/**\n * Represents an actor in Plot - a user, contact, or twist.\n *\n * Actors can be associated with threads as authors, assignees, or mentions.\n * The email field is only included when ContactAccess.Read permission is granted.\n *\n * @example\n * ```typescript\n * const actor: Actor = {\n * id: \"f0ffd5f8-1635-4b13-9532-35f97446db90\" as ActorId,\n * type: ActorType.Contact,\n * email: \"john.doe@example.com\", // Only if ContactAccess.Read\n * name: \"John Doe\"\n * };\n * ```\n */\nexport type Actor = {\n /** Unique identifier for the actor */\n id: ActorId;\n /** Type of actor (User, Contact, or Twist) */\n type: ActorType;\n /**\n * Email address (only included with ContactAccess.Read permission).\n * - `undefined`: No permission to read email\n * - `null`: Permission granted but email not set\n * - `string`: Email address\n */\n email?: string | null;\n /**\n * Display name.\n * - `undefined`: Not included due to permissions\n * - `null`: Not set\n * - `string`: Display name\n */\n name?: string | null;\n};\n\n/**\n * A resolved contact with identity info. Used for access control lists\n * where only human contacts (not twists) are relevant.\n */\nexport type Contact = {\n /** Unique identifier for the contact */\n id: ActorId;\n /** Email address, or null if not set */\n email: string | null;\n /** Display name, or null if not set */\n name: string | null;\n};\n\n/**\n * An existing or new contact.\n */\nexport type NewActor =\n | {\n /** Unique identifier for the actor */\n id: ActorId;\n }\n | NewContact;\n\n/**\n * Enumeration of author types that can create threads.\n *\n * The author type affects how threads are displayed and processed\n * within the Plot system.\n */\nexport enum ActorType {\n /** Threads created by human users */\n User,\n /** Threads created by external contacts */\n Contact,\n /** Threads created by automated twists */\n Twist,\n}\n\n/**\n * Represents contact information for creating a new contact.\n *\n * Contacts are used throughout Plot for representing people associated\n * with activities, such as event attendees or task assignees.\n *\n * @example\n * ```typescript\n * const newContact: NewContact = {\n * email: \"john.doe@example.com\",\n * name: \"John Doe\",\n * avatar: \"https://avatar.example.com/john.jpg\"\n * };\n * ```\n */\n/**\n * Common fields shared by all NewContact variants.\n */\ntype NewContactBase = {\n /** Optional avatar image URL for the contact */\n avatar?: string;\n /**\n * External provider account source. Used for identity resolution\n * when email is unavailable and for privacy compliance reporting.\n *\n * The runtime scopes the resulting `contact_external_account` row to\n * the dispatching twist instance (i.e. one row per connection per\n * contact), so the same Plot contact can have multiple rows when\n * reachable through multiple connections (e.g. two Slack workspaces,\n * Gmail + Google Chat sharing one Google account).\n */\n source?: { accountId: string };\n /**\n * Optional connector-defined role for this contact on the thread, matching\n * a `LinkTypeConfig.contactRoles[].id` (e.g. \"to\" / \"cc\" / \"bcc\" for\n * email, \"required\" / \"optional\" for calendar). Omitted ⇒ default role.\n * Connectors set this on inbound sync; the runtime persists it under\n * `thread.contact_meta[contact_id].role`.\n */\n role?: string;\n};\n\n/**\n * At least one of `email` or `name` must be provided so the contact can be\n * identified in the UI. Contacts with neither would display as \"Unknown\".\n */\nexport type NewContact = NewContactBase &\n ({ email: string; name?: string } | { email?: string; name: string });\n\nexport type ContentType = \"text\" | \"markdown\" | \"html\";\n\n/**\n * Represents an external entity linked to a thread.\n *\n * Links are created by sources to represent external entities (issues, emails, calendar events)\n * attached to a thread container. A thread can have multiple links (1:many).\n * Links store source-specific data like type, status, metadata, and embeddings.\n *\n * @example\n * ```typescript\n * // A link representing a Linear issue\n * const link: Link = {\n * threadId: \"...\" as Uuid,\n * source: \"linear:issue:549dd8bd-2bc9-43d1-95d5-4b4af0c5af1b\",\n * created: new Date(),\n * author: { id: \"...\" as ActorId, type: ActorType.Contact, name: \"Alice\" },\n * title: \"Fix login bug\",\n * type: \"issue\",\n * status: \"open\",\n * meta: { projectId: \"TEAM\", url: \"https://linear.app/team/TEAM-123\" },\n * assignee: null,\n * actions: null,\n * };\n * ```\n */\nexport type Link = {\n /** The thread this link belongs to */\n threadId: Uuid;\n /** External source identifier for dedup/upsert */\n source: string | null;\n /** When this link was originally created in its source system */\n created: Date;\n /** The actor credited with creating this link */\n author: Actor | null;\n /** Display title */\n title: string;\n /** Truncated preview */\n preview: string | null;\n /** The actor assigned to this link */\n assignee: Actor | null;\n /** Source-defined type string (e.g., issue, pull_request, email, event) */\n type: string | null;\n /** Source-defined status string (e.g., open, done, closed) */\n status: string | null;\n /** Interactive action buttons */\n actions: Array<Action> | null;\n /** Source metadata */\n meta: ThreadMeta | null;\n /** URL to open the original item in its source application (e.g., \"Open in Linear\") */\n sourceUrl: string | null;\n /** Channel ID that produced this link (matches source_channel.channel_id) */\n channelId: string | null;\n /**\n * Cross-connector thread bundling key.\n *\n * @deprecated Use `sources` instead. Reads return the first element of\n * `sources` for backward compatibility; new writes should populate `sources`.\n */\n relatedSource: string | null;\n /**\n * Canonical identifiers for this link. Two links whose `sources` arrays\n * overlap share the same thread (array overlap, `sources && new.sources`).\n *\n * Use this to bundle with another connector via a canonical alias. For\n * example, every calendar connector emits `icaluid:<iCalUID>` so any\n * meeting-notes connector can bundle by setting the same alias.\n */\n sources: string[];\n};\n\n/**\n * Type for creating new links.\n *\n * Links are created by sources to represent external entities.\n * Requires a source identifier for dedup/upsert.\n */\nexport type NewLink = Partial<\n Omit<Link, \"author\" | \"assignee\" | \"threadId\">\n> & {\n /**\n * Canonical ID for the item in an external system.\n * When set, uniquely identifies the link for the user. This performs\n * an upsert.\n *\n * @deprecated Pass `sources: [...]` instead. Both fields can be set during\n * the transition; the runtime will normalize.\n */\n source?: string;\n /**\n * Canonical identifiers for this item. Any element shared with another\n * link's `sources` bundles the two links into the same thread. Used for\n * cross-connector bundling — e.g. a meeting-notes connector setting\n * `[\"granola:<id>\", \"icaluid:<uid>\"]` to attach onto a calendar event\n * thread that includes `icaluid:<uid>` in its own `sources`.\n */\n sources?: string[];\n /** The person that created the item. By default, it will be the twist itself. */\n author?: NewActor;\n /** The person assigned to the item. */\n assignee?: NewActor | null;\n /**\n * Thread access level: \"public\", \"members\" (default), or \"private\".\n * When \"private\", thread visibility is limited to the creator and contacts in accessContacts.\n */\n access?: ThreadAccessLevel;\n /**\n * Contacts who can see a private thread.\n * Pass email-based NewContact objects; they are resolved to contact IDs by the API.\n * If omitted for a private thread, defaults to the connection owner.\n */\n accessContacts?: NewContact[];\n /**\n * Whether the thread should be marked as unread for users.\n * - undefined/omitted (default): Thread is unread for users, except auto-marked\n * as read for the author if they are the twist owner (user)\n * - false: Thread is marked as read for all users in the focus at creation time\n */\n unread?: boolean;\n /**\n * Whether the thread is archived.\n * - true: Archive the thread\n * - false: Unarchive the thread\n * - undefined (default): Preserve current archive state\n */\n archived?: boolean;\n /**\n * Explicit focus (disables automatic focus matching).\n * Only used when the link creates a new thread. When omitted, the\n * server classifies the thread using the user's focus rules.\n */\n focus?: Pick<Focus, \"id\">;\n };\n\n/**\n * A new link with notes to save via integrations.saveLink().\n * Creates a thread+link pair, with notes attached to the thread.\n */\nexport type NewLinkWithNotes = NewLink & {\n /**\n * Title for the link and its thread container.\n * Must be the real entity title (e.g. issue title, message subject),\n * never a placeholder or ID. This value overwrites the existing title on upsert.\n * Omit to preserve the existing title (e.g. for cancelled events where the\n * title may not be available in the webhook payload).\n */\n title?: string;\n /** Notes to attach to the thread */\n notes?: Omit<NewNote, \"thread\">[];\n /** Schedules to create for the link */\n schedules?: Array<Omit<NewSchedule, \"threadId\">>;\n /** Schedule occurrence overrides */\n scheduleOccurrences?: NewScheduleOccurrence[];\n};\n\n/**\n * Type for updating existing links.\n *\n * Set `threadId` to move the link to a different thread.\n * Requires LinkAccess.Full.\n */\nexport type LinkUpdate = { id: Uuid } & {\n /** Move the link to a different thread owned by the twist's user. */\n threadId?: Uuid;\n};\n\n/**\n * A single operation within a plan submitted for user approval.\n *\n * Operations include display metadata (titles) so the app can render\n * a human-readable summary without additional lookups.\n */\nexport type PlanOperation =\n | {\n type: \"updateThread\";\n threadId: Uuid;\n /** Current thread title for display */\n threadTitle: string;\n changes: Partial<Pick<ThreadFields, \"archived\" | \"title\" | \"type\">> & {\n /** Move to this focus */\n focus?: { id: Uuid; title: string };\n };\n }\n | {\n type: \"updateLink\";\n linkId: Uuid;\n /** Current link title for display */\n linkTitle: string;\n changes: {\n /** Move to this thread */\n threadId?: Uuid;\n threadTitle?: string;\n };\n }\n | {\n type: \"createThread\";\n title: string;\n focusId: Uuid;\n /** Focus title for display */\n focusTitle: string;\n }\n | {\n type: \"createNote\";\n threadId: Uuid;\n /** Thread title for display */\n threadTitle: string;\n content: string;\n }\n | {\n type: \"updateFocus\";\n focusId: Uuid;\n /** Current focus title for display */\n focusTitle: string;\n changes: Partial<Pick<Focus, \"title\" | \"archived\">>;\n };\n";
8
8
  //# sourceMappingURL=plot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plot.js","sourceRoot":"","sources":["../../src/llm-docs/plot.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAe,gsoCAAgsoC,CAAC"}
1
+ {"version":3,"file":"plot.js","sourceRoot":"","sources":["../../src/llm-docs/plot.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAe,khuCAAkhuC,CAAC"}
@@ -4,6 +4,6 @@
4
4
  * This file is auto-generated during build. Do not edit manually.
5
5
  * Generated from: prebuild.ts
6
6
  */
7
- declare const _default: "import { type Tag } from \"./tag\";\nimport {\n type Actor,\n type ActorId,\n type NewActor,\n type NewTags,\n type Tags,\n} from \"./plot\";\nimport { Uuid } from \"./utils/uuid\";\n\nexport { Uuid } from \"./utils/uuid\";\n\n/**\n * Represents a schedule entry for a thread.\n *\n * Schedules define when a thread occurs in time. A thread may have zero or more schedules:\n * - Shared schedules (userId is null): visible to all members of the thread's priority\n * - Per-user schedules (userId set): private ordering/scheduling for a specific user\n *\n * For recurring events in the SDK, start/end represent the first occurrence's\n * time. In the database, the `at`/`on` range is expanded to span from the first\n * occurrence start to the last occurrence end (or open-ended if no fixed end).\n * The `duration` column stores the per-occurrence duration, enabling range overlap\n * queries to correctly find all recurring events with occurrences in a given window.\n */\nexport type Schedule = {\n /** When this schedule was created */\n created: Date;\n /** Whether this schedule has been archived */\n archived: boolean;\n /** If set, this is a per-user schedule visible only to this user */\n userId: ActorId | null;\n /** Per-user ordering within a day (only set for per-user schedules) */\n order: number | null;\n /**\n * Start time of the schedule.\n * Date object for timed events, date string in \"YYYY-MM-DD\" format for all-day events.\n */\n start: Date | string | null;\n /**\n * End time of the schedule.\n * Date object for timed events, date string in \"YYYY-MM-DD\" format for all-day events.\n */\n end: Date | string | null;\n /** Recurrence rule in RFC 5545 RRULE format (e.g., \"FREQ=WEEKLY;BYDAY=MO,WE,FR\") */\n recurrenceRule: string | null;\n /** Duration of each occurrence in milliseconds (required for recurring schedules) */\n duration: number | null;\n /** Array of dates to exclude from the recurrence pattern */\n recurrenceExdates: Date[] | null;\n /**\n * For occurrence exceptions: the original date/time of this occurrence in the series.\n * Format: Date object or \"YYYY-MM-DD\" for all-day events.\n */\n occurrence: Date | string | null;\n /** Contacts invited to this schedule (attendees/participants) */\n contacts: ScheduleContact[];\n};\n\nexport type ScheduleContactStatus = \"attend\" | \"skip\";\nexport type ScheduleContactRole = \"organizer\" | \"required\" | \"optional\";\n\nexport type ScheduleContact = {\n contact: Actor;\n status: ScheduleContactStatus | null;\n role: ScheduleContactRole;\n archived: boolean;\n};\n\nexport type NewScheduleContact = {\n contact: NewActor;\n status?: ScheduleContactStatus | null;\n role?: ScheduleContactRole | null;\n archived?: boolean;\n};\n\n/**\n * Type for creating new schedules.\n *\n * Requires `threadId` and `start`. All other fields are optional.\n *\n * @example\n * ```typescript\n * // Simple timed event\n * const schedule: NewSchedule = {\n * threadId: threadId,\n * start: new Date(\"2025-03-15T10:00:00Z\"),\n * end: new Date(\"2025-03-15T11:00:00Z\")\n * };\n *\n * // All-day event\n * const allDay: NewSchedule = {\n * threadId: threadId,\n * start: \"2025-03-15\",\n * end: \"2025-03-16\"\n * };\n *\n * // Recurring weekly event\n * const recurring: NewSchedule = {\n * threadId: threadId,\n * start: new Date(\"2025-01-20T14:00:00Z\"),\n * end: new Date(\"2025-01-20T15:00:00Z\"),\n * recurrenceRule: \"FREQ=WEEKLY;BYDAY=MO\",\n * recurrenceUntil: new Date(\"2025-06-30\")\n * };\n * ```\n */\nexport type NewSchedule = {\n /** The thread this schedule belongs to */\n threadId: Uuid;\n /**\n * Start time. Date for timed events, \"YYYY-MM-DD\" for all-day.\n * Determines whether the schedule uses `at` (timed) or `on` (all-day) storage.\n */\n start: Date | string;\n /** End time. Date for timed events, \"YYYY-MM-DD\" for all-day. */\n end?: Date | string | null;\n /** Recurrence rule in RFC 5545 RRULE format */\n recurrenceRule?: string | null;\n /**\n * For recurring schedules, the last occurrence date (inclusive).\n * When both recurrenceCount and recurrenceUntil are provided, recurrenceCount takes precedence.\n */\n recurrenceUntil?: Date | string | null;\n /**\n * For recurring schedules, the number of occurrences to generate.\n * Takes precedence over recurrenceUntil if both are provided.\n */\n recurrenceCount?: number | null;\n /** Array of dates to exclude from the recurrence pattern */\n recurrenceExdates?: Date[] | null;\n /**\n * For occurrence exceptions: the original date/time of this occurrence.\n */\n occurrence?: Date | string | null;\n /** If set, this is a per-user schedule for the specified user */\n userId?: ActorId | null;\n /** Per-user ordering (only valid with userId) */\n order?: number | null;\n /** Whether to archive this schedule */\n archived?: boolean;\n /** Contacts to upsert on this schedule. Upserted by contact identity. */\n contacts?: NewScheduleContact[];\n};\n\n/**\n * Represents a specific instance of a recurring schedule.\n * All field values are computed by merging the recurring schedule's\n * defaults with any occurrence-specific overrides.\n */\nexport type ScheduleOccurrence = {\n /**\n * Original date/datetime of this occurrence.\n * Use start for the occurrence's current start time.\n */\n occurrence: Date | string;\n\n /** The recurring schedule of which this is an occurrence */\n schedule: Schedule;\n\n /** Effective start for this occurrence (series default + override) */\n start: Date | string;\n /** Effective end for this occurrence */\n end: Date | string | null;\n\n /** Tags for this occurrence */\n tags: Tags;\n};\n\n/**\n * Type for creating or updating schedule occurrences.\n *\n * Use `cancelled: true` to skip a single date in a recurring series\n * (e.g. an upstream calendar reports one occurrence as cancelled).\n * Internally this is translated into an addition to the parent\n * schedule's `recurrenceExdates`; no occurrence schedule row is\n * persisted for the cancelled date. For seeding the full exception\n * list on the master at initial sync, use `NewSchedule.recurrenceExdates`\n * instead.\n *\n * Use a normal occurrence record (without `cancelled`) for genuine\n * overrides \u2014 time changes, RSVP differences, etc.\n */\nexport type NewScheduleOccurrence = Pick<\n ScheduleOccurrence,\n \"occurrence\" | \"start\"\n> &\n Partial<\n Omit<ScheduleOccurrence, \"occurrence\" | \"start\" | \"schedule\" | \"tags\">\n > & {\n /** Tags for this occurrence */\n tags?: NewTags;\n\n /** Add or remove the twist's tags on this occurrence */\n twistTags?: Partial<Record<Tag, boolean>>;\n\n /** Whether this occurrence should be marked as unread */\n unread?: boolean;\n\n /** Contacts to upsert on this occurrence's schedule */\n contacts?: NewScheduleContact[];\n\n /**\n * Mark this single date as cancelled. The runtime translates this\n * into an addition to the parent schedule's `recurrenceExdates` and\n * archives any pre-existing override row for the same date \u2014 no\n * occurrence schedule row is created.\n */\n cancelled?: boolean;\n };\n\n/**\n * Type for updating schedule occurrences inline.\n */\nexport type ScheduleOccurrenceUpdate = Pick<\n NewScheduleOccurrence,\n \"occurrence\"\n> &\n Partial<Omit<NewScheduleOccurrence, \"occurrence\" | \"schedule\">>;\n";
7
+ declare const _default: "import { type Tag } from \"./tag\";\nimport {\n type Actor,\n type ActorId,\n type NewActor,\n type NewTags,\n type Tags,\n} from \"./plot\";\nimport { Uuid } from \"./utils/uuid\";\n\nexport { Uuid } from \"./utils/uuid\";\n\n/**\n * Represents a schedule entry for a thread.\n *\n * Schedules define when a thread occurs in time. A thread may have zero or more schedules:\n * - Shared schedules (userId is null): visible to all members of the thread's focus\n * - Per-user schedules (userId set): private ordering/scheduling for a specific user\n *\n * For recurring events in the SDK, start/end represent the first occurrence's\n * time. In the database, the `at`/`on` range is expanded to span from the first\n * occurrence start to the last occurrence end (or open-ended if no fixed end).\n * The `duration` column stores the per-occurrence duration, enabling range overlap\n * queries to correctly find all recurring events with occurrences in a given window.\n */\nexport type Schedule = {\n /** When this schedule was created */\n created: Date;\n /** Whether this schedule has been archived */\n archived: boolean;\n /** If set, this is a per-user schedule visible only to this user */\n userId: ActorId | null;\n /** Per-user ordering within a day (only set for per-user schedules) */\n order: number | null;\n /**\n * Start time of the schedule.\n * Date object for timed events, date string in \"YYYY-MM-DD\" format for all-day events.\n */\n start: Date | string | null;\n /**\n * End time of the schedule.\n * Date object for timed events, date string in \"YYYY-MM-DD\" format for all-day events.\n */\n end: Date | string | null;\n /** Recurrence rule in RFC 5545 RRULE format (e.g., \"FREQ=WEEKLY;BYDAY=MO,WE,FR\") */\n recurrenceRule: string | null;\n /** Duration of each occurrence in milliseconds (required for recurring schedules) */\n duration: number | null;\n /** Array of dates to exclude from the recurrence pattern */\n recurrenceExdates: Date[] | null;\n /**\n * For occurrence exceptions: the original date/time of this occurrence in the series.\n * Format: Date object or \"YYYY-MM-DD\" for all-day events.\n */\n occurrence: Date | string | null;\n /** Contacts invited to this schedule (attendees/participants) */\n contacts: ScheduleContact[];\n};\n\nexport type ScheduleContactStatus = \"attend\" | \"skip\";\nexport type ScheduleContactRole = \"organizer\" | \"required\" | \"optional\";\n\nexport type ScheduleContact = {\n contact: Actor;\n status: ScheduleContactStatus | null;\n role: ScheduleContactRole;\n archived: boolean;\n};\n\nexport type NewScheduleContact = {\n contact: NewActor;\n status?: ScheduleContactStatus | null;\n role?: ScheduleContactRole | null;\n archived?: boolean;\n};\n\n/**\n * Type for creating new schedules.\n *\n * Requires `threadId` and `start`. All other fields are optional.\n *\n * @example\n * ```typescript\n * // Simple timed event\n * const schedule: NewSchedule = {\n * threadId: threadId,\n * start: new Date(\"2025-03-15T10:00:00Z\"),\n * end: new Date(\"2025-03-15T11:00:00Z\")\n * };\n *\n * // All-day event\n * const allDay: NewSchedule = {\n * threadId: threadId,\n * start: \"2025-03-15\",\n * end: \"2025-03-16\"\n * };\n *\n * // Recurring weekly event\n * const recurring: NewSchedule = {\n * threadId: threadId,\n * start: new Date(\"2025-01-20T14:00:00Z\"),\n * end: new Date(\"2025-01-20T15:00:00Z\"),\n * recurrenceRule: \"FREQ=WEEKLY;BYDAY=MO\",\n * recurrenceUntil: new Date(\"2025-06-30\")\n * };\n * ```\n */\nexport type NewSchedule = {\n /** The thread this schedule belongs to */\n threadId: Uuid;\n /**\n * Start time. Date for timed events, \"YYYY-MM-DD\" for all-day.\n * Determines whether the schedule uses `at` (timed) or `on` (all-day) storage.\n */\n start: Date | string;\n /** End time. Date for timed events, \"YYYY-MM-DD\" for all-day. */\n end?: Date | string | null;\n /** Recurrence rule in RFC 5545 RRULE format */\n recurrenceRule?: string | null;\n /**\n * For recurring schedules, the last occurrence date (inclusive).\n * When both recurrenceCount and recurrenceUntil are provided, recurrenceCount takes precedence.\n */\n recurrenceUntil?: Date | string | null;\n /**\n * For recurring schedules, the number of occurrences to generate.\n * Takes precedence over recurrenceUntil if both are provided.\n */\n recurrenceCount?: number | null;\n /** Array of dates to exclude from the recurrence pattern */\n recurrenceExdates?: Date[] | null;\n /**\n * For occurrence exceptions: the original date/time of this occurrence.\n */\n occurrence?: Date | string | null;\n /** If set, this is a per-user schedule for the specified user */\n userId?: ActorId | null;\n /** Per-user ordering (only valid with userId) */\n order?: number | null;\n /** Whether to archive this schedule */\n archived?: boolean;\n /** Contacts to upsert on this schedule. Upserted by contact identity. */\n contacts?: NewScheduleContact[];\n};\n\n/**\n * Represents a specific instance of a recurring schedule.\n * All field values are computed by merging the recurring schedule's\n * defaults with any occurrence-specific overrides.\n */\nexport type ScheduleOccurrence = {\n /**\n * Original date/datetime of this occurrence.\n * Use start for the occurrence's current start time.\n */\n occurrence: Date | string;\n\n /** The recurring schedule of which this is an occurrence */\n schedule: Schedule;\n\n /** Effective start for this occurrence (series default + override) */\n start: Date | string;\n /** Effective end for this occurrence */\n end: Date | string | null;\n\n /** Tags for this occurrence */\n tags: Tags;\n};\n\n/**\n * Type for creating or updating schedule occurrences.\n *\n * Use `cancelled: true` to skip a single date in a recurring series\n * (e.g. an upstream calendar reports one occurrence as cancelled).\n * Internally this is translated into an addition to the parent\n * schedule's `recurrenceExdates`; no occurrence schedule row is\n * persisted for the cancelled date. For seeding the full exception\n * list on the master at initial sync, use `NewSchedule.recurrenceExdates`\n * instead.\n *\n * Use a normal occurrence record (without `cancelled`) for genuine\n * overrides \u2014 time changes, RSVP differences, etc.\n */\nexport type NewScheduleOccurrence = Pick<\n ScheduleOccurrence,\n \"occurrence\" | \"start\"\n> &\n Partial<\n Omit<ScheduleOccurrence, \"occurrence\" | \"start\" | \"schedule\" | \"tags\">\n > & {\n /** Tags for this occurrence */\n tags?: NewTags;\n\n /** Add or remove the twist's tags on this occurrence */\n twistTags?: Partial<Record<Tag, boolean>>;\n\n /** Whether this occurrence should be marked as unread */\n unread?: boolean;\n\n /** Contacts to upsert on this occurrence's schedule */\n contacts?: NewScheduleContact[];\n\n /**\n * Mark this single date as cancelled. The runtime translates this\n * into an addition to the parent schedule's `recurrenceExdates` and\n * archives any pre-existing override row for the same date \u2014 no\n * occurrence schedule row is created.\n */\n cancelled?: boolean;\n };\n\n/**\n * Type for updating schedule occurrences inline.\n */\nexport type ScheduleOccurrenceUpdate = Pick<\n NewScheduleOccurrence,\n \"occurrence\"\n> &\n Partial<Omit<NewScheduleOccurrence, \"occurrence\" | \"schedule\">>;\n";
8
8
  export default _default;
9
9
  //# sourceMappingURL=schedule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../../src/llm-docs/schedule.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;wBAEY,m1OAAy0O;AAAx1O,wBAAy1O"}
1
+ {"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../../src/llm-docs/schedule.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;wBAEY,g1OAAs0O;AAAr1O,wBAAs1O"}
@@ -4,5 +4,5 @@
4
4
  * This file is auto-generated during build. Do not edit manually.
5
5
  * Generated from: prebuild.ts
6
6
  */
7
- export default "import { type Tag } from \"./tag\";\nimport {\n type Actor,\n type ActorId,\n type NewActor,\n type NewTags,\n type Tags,\n} from \"./plot\";\nimport { Uuid } from \"./utils/uuid\";\n\nexport { Uuid } from \"./utils/uuid\";\n\n/**\n * Represents a schedule entry for a thread.\n *\n * Schedules define when a thread occurs in time. A thread may have zero or more schedules:\n * - Shared schedules (userId is null): visible to all members of the thread's priority\n * - Per-user schedules (userId set): private ordering/scheduling for a specific user\n *\n * For recurring events in the SDK, start/end represent the first occurrence's\n * time. In the database, the `at`/`on` range is expanded to span from the first\n * occurrence start to the last occurrence end (or open-ended if no fixed end).\n * The `duration` column stores the per-occurrence duration, enabling range overlap\n * queries to correctly find all recurring events with occurrences in a given window.\n */\nexport type Schedule = {\n /** When this schedule was created */\n created: Date;\n /** Whether this schedule has been archived */\n archived: boolean;\n /** If set, this is a per-user schedule visible only to this user */\n userId: ActorId | null;\n /** Per-user ordering within a day (only set for per-user schedules) */\n order: number | null;\n /**\n * Start time of the schedule.\n * Date object for timed events, date string in \"YYYY-MM-DD\" format for all-day events.\n */\n start: Date | string | null;\n /**\n * End time of the schedule.\n * Date object for timed events, date string in \"YYYY-MM-DD\" format for all-day events.\n */\n end: Date | string | null;\n /** Recurrence rule in RFC 5545 RRULE format (e.g., \"FREQ=WEEKLY;BYDAY=MO,WE,FR\") */\n recurrenceRule: string | null;\n /** Duration of each occurrence in milliseconds (required for recurring schedules) */\n duration: number | null;\n /** Array of dates to exclude from the recurrence pattern */\n recurrenceExdates: Date[] | null;\n /**\n * For occurrence exceptions: the original date/time of this occurrence in the series.\n * Format: Date object or \"YYYY-MM-DD\" for all-day events.\n */\n occurrence: Date | string | null;\n /** Contacts invited to this schedule (attendees/participants) */\n contacts: ScheduleContact[];\n};\n\nexport type ScheduleContactStatus = \"attend\" | \"skip\";\nexport type ScheduleContactRole = \"organizer\" | \"required\" | \"optional\";\n\nexport type ScheduleContact = {\n contact: Actor;\n status: ScheduleContactStatus | null;\n role: ScheduleContactRole;\n archived: boolean;\n};\n\nexport type NewScheduleContact = {\n contact: NewActor;\n status?: ScheduleContactStatus | null;\n role?: ScheduleContactRole | null;\n archived?: boolean;\n};\n\n/**\n * Type for creating new schedules.\n *\n * Requires `threadId` and `start`. All other fields are optional.\n *\n * @example\n * ```typescript\n * // Simple timed event\n * const schedule: NewSchedule = {\n * threadId: threadId,\n * start: new Date(\"2025-03-15T10:00:00Z\"),\n * end: new Date(\"2025-03-15T11:00:00Z\")\n * };\n *\n * // All-day event\n * const allDay: NewSchedule = {\n * threadId: threadId,\n * start: \"2025-03-15\",\n * end: \"2025-03-16\"\n * };\n *\n * // Recurring weekly event\n * const recurring: NewSchedule = {\n * threadId: threadId,\n * start: new Date(\"2025-01-20T14:00:00Z\"),\n * end: new Date(\"2025-01-20T15:00:00Z\"),\n * recurrenceRule: \"FREQ=WEEKLY;BYDAY=MO\",\n * recurrenceUntil: new Date(\"2025-06-30\")\n * };\n * ```\n */\nexport type NewSchedule = {\n /** The thread this schedule belongs to */\n threadId: Uuid;\n /**\n * Start time. Date for timed events, \"YYYY-MM-DD\" for all-day.\n * Determines whether the schedule uses `at` (timed) or `on` (all-day) storage.\n */\n start: Date | string;\n /** End time. Date for timed events, \"YYYY-MM-DD\" for all-day. */\n end?: Date | string | null;\n /** Recurrence rule in RFC 5545 RRULE format */\n recurrenceRule?: string | null;\n /**\n * For recurring schedules, the last occurrence date (inclusive).\n * When both recurrenceCount and recurrenceUntil are provided, recurrenceCount takes precedence.\n */\n recurrenceUntil?: Date | string | null;\n /**\n * For recurring schedules, the number of occurrences to generate.\n * Takes precedence over recurrenceUntil if both are provided.\n */\n recurrenceCount?: number | null;\n /** Array of dates to exclude from the recurrence pattern */\n recurrenceExdates?: Date[] | null;\n /**\n * For occurrence exceptions: the original date/time of this occurrence.\n */\n occurrence?: Date | string | null;\n /** If set, this is a per-user schedule for the specified user */\n userId?: ActorId | null;\n /** Per-user ordering (only valid with userId) */\n order?: number | null;\n /** Whether to archive this schedule */\n archived?: boolean;\n /** Contacts to upsert on this schedule. Upserted by contact identity. */\n contacts?: NewScheduleContact[];\n};\n\n/**\n * Represents a specific instance of a recurring schedule.\n * All field values are computed by merging the recurring schedule's\n * defaults with any occurrence-specific overrides.\n */\nexport type ScheduleOccurrence = {\n /**\n * Original date/datetime of this occurrence.\n * Use start for the occurrence's current start time.\n */\n occurrence: Date | string;\n\n /** The recurring schedule of which this is an occurrence */\n schedule: Schedule;\n\n /** Effective start for this occurrence (series default + override) */\n start: Date | string;\n /** Effective end for this occurrence */\n end: Date | string | null;\n\n /** Tags for this occurrence */\n tags: Tags;\n};\n\n/**\n * Type for creating or updating schedule occurrences.\n *\n * Use `cancelled: true` to skip a single date in a recurring series\n * (e.g. an upstream calendar reports one occurrence as cancelled).\n * Internally this is translated into an addition to the parent\n * schedule's `recurrenceExdates`; no occurrence schedule row is\n * persisted for the cancelled date. For seeding the full exception\n * list on the master at initial sync, use `NewSchedule.recurrenceExdates`\n * instead.\n *\n * Use a normal occurrence record (without `cancelled`) for genuine\n * overrides — time changes, RSVP differences, etc.\n */\nexport type NewScheduleOccurrence = Pick<\n ScheduleOccurrence,\n \"occurrence\" | \"start\"\n> &\n Partial<\n Omit<ScheduleOccurrence, \"occurrence\" | \"start\" | \"schedule\" | \"tags\">\n > & {\n /** Tags for this occurrence */\n tags?: NewTags;\n\n /** Add or remove the twist's tags on this occurrence */\n twistTags?: Partial<Record<Tag, boolean>>;\n\n /** Whether this occurrence should be marked as unread */\n unread?: boolean;\n\n /** Contacts to upsert on this occurrence's schedule */\n contacts?: NewScheduleContact[];\n\n /**\n * Mark this single date as cancelled. The runtime translates this\n * into an addition to the parent schedule's `recurrenceExdates` and\n * archives any pre-existing override row for the same date — no\n * occurrence schedule row is created.\n */\n cancelled?: boolean;\n };\n\n/**\n * Type for updating schedule occurrences inline.\n */\nexport type ScheduleOccurrenceUpdate = Pick<\n NewScheduleOccurrence,\n \"occurrence\"\n> &\n Partial<Omit<NewScheduleOccurrence, \"occurrence\" | \"schedule\">>;\n";
7
+ export default "import { type Tag } from \"./tag\";\nimport {\n type Actor,\n type ActorId,\n type NewActor,\n type NewTags,\n type Tags,\n} from \"./plot\";\nimport { Uuid } from \"./utils/uuid\";\n\nexport { Uuid } from \"./utils/uuid\";\n\n/**\n * Represents a schedule entry for a thread.\n *\n * Schedules define when a thread occurs in time. A thread may have zero or more schedules:\n * - Shared schedules (userId is null): visible to all members of the thread's focus\n * - Per-user schedules (userId set): private ordering/scheduling for a specific user\n *\n * For recurring events in the SDK, start/end represent the first occurrence's\n * time. In the database, the `at`/`on` range is expanded to span from the first\n * occurrence start to the last occurrence end (or open-ended if no fixed end).\n * The `duration` column stores the per-occurrence duration, enabling range overlap\n * queries to correctly find all recurring events with occurrences in a given window.\n */\nexport type Schedule = {\n /** When this schedule was created */\n created: Date;\n /** Whether this schedule has been archived */\n archived: boolean;\n /** If set, this is a per-user schedule visible only to this user */\n userId: ActorId | null;\n /** Per-user ordering within a day (only set for per-user schedules) */\n order: number | null;\n /**\n * Start time of the schedule.\n * Date object for timed events, date string in \"YYYY-MM-DD\" format for all-day events.\n */\n start: Date | string | null;\n /**\n * End time of the schedule.\n * Date object for timed events, date string in \"YYYY-MM-DD\" format for all-day events.\n */\n end: Date | string | null;\n /** Recurrence rule in RFC 5545 RRULE format (e.g., \"FREQ=WEEKLY;BYDAY=MO,WE,FR\") */\n recurrenceRule: string | null;\n /** Duration of each occurrence in milliseconds (required for recurring schedules) */\n duration: number | null;\n /** Array of dates to exclude from the recurrence pattern */\n recurrenceExdates: Date[] | null;\n /**\n * For occurrence exceptions: the original date/time of this occurrence in the series.\n * Format: Date object or \"YYYY-MM-DD\" for all-day events.\n */\n occurrence: Date | string | null;\n /** Contacts invited to this schedule (attendees/participants) */\n contacts: ScheduleContact[];\n};\n\nexport type ScheduleContactStatus = \"attend\" | \"skip\";\nexport type ScheduleContactRole = \"organizer\" | \"required\" | \"optional\";\n\nexport type ScheduleContact = {\n contact: Actor;\n status: ScheduleContactStatus | null;\n role: ScheduleContactRole;\n archived: boolean;\n};\n\nexport type NewScheduleContact = {\n contact: NewActor;\n status?: ScheduleContactStatus | null;\n role?: ScheduleContactRole | null;\n archived?: boolean;\n};\n\n/**\n * Type for creating new schedules.\n *\n * Requires `threadId` and `start`. All other fields are optional.\n *\n * @example\n * ```typescript\n * // Simple timed event\n * const schedule: NewSchedule = {\n * threadId: threadId,\n * start: new Date(\"2025-03-15T10:00:00Z\"),\n * end: new Date(\"2025-03-15T11:00:00Z\")\n * };\n *\n * // All-day event\n * const allDay: NewSchedule = {\n * threadId: threadId,\n * start: \"2025-03-15\",\n * end: \"2025-03-16\"\n * };\n *\n * // Recurring weekly event\n * const recurring: NewSchedule = {\n * threadId: threadId,\n * start: new Date(\"2025-01-20T14:00:00Z\"),\n * end: new Date(\"2025-01-20T15:00:00Z\"),\n * recurrenceRule: \"FREQ=WEEKLY;BYDAY=MO\",\n * recurrenceUntil: new Date(\"2025-06-30\")\n * };\n * ```\n */\nexport type NewSchedule = {\n /** The thread this schedule belongs to */\n threadId: Uuid;\n /**\n * Start time. Date for timed events, \"YYYY-MM-DD\" for all-day.\n * Determines whether the schedule uses `at` (timed) or `on` (all-day) storage.\n */\n start: Date | string;\n /** End time. Date for timed events, \"YYYY-MM-DD\" for all-day. */\n end?: Date | string | null;\n /** Recurrence rule in RFC 5545 RRULE format */\n recurrenceRule?: string | null;\n /**\n * For recurring schedules, the last occurrence date (inclusive).\n * When both recurrenceCount and recurrenceUntil are provided, recurrenceCount takes precedence.\n */\n recurrenceUntil?: Date | string | null;\n /**\n * For recurring schedules, the number of occurrences to generate.\n * Takes precedence over recurrenceUntil if both are provided.\n */\n recurrenceCount?: number | null;\n /** Array of dates to exclude from the recurrence pattern */\n recurrenceExdates?: Date[] | null;\n /**\n * For occurrence exceptions: the original date/time of this occurrence.\n */\n occurrence?: Date | string | null;\n /** If set, this is a per-user schedule for the specified user */\n userId?: ActorId | null;\n /** Per-user ordering (only valid with userId) */\n order?: number | null;\n /** Whether to archive this schedule */\n archived?: boolean;\n /** Contacts to upsert on this schedule. Upserted by contact identity. */\n contacts?: NewScheduleContact[];\n};\n\n/**\n * Represents a specific instance of a recurring schedule.\n * All field values are computed by merging the recurring schedule's\n * defaults with any occurrence-specific overrides.\n */\nexport type ScheduleOccurrence = {\n /**\n * Original date/datetime of this occurrence.\n * Use start for the occurrence's current start time.\n */\n occurrence: Date | string;\n\n /** The recurring schedule of which this is an occurrence */\n schedule: Schedule;\n\n /** Effective start for this occurrence (series default + override) */\n start: Date | string;\n /** Effective end for this occurrence */\n end: Date | string | null;\n\n /** Tags for this occurrence */\n tags: Tags;\n};\n\n/**\n * Type for creating or updating schedule occurrences.\n *\n * Use `cancelled: true` to skip a single date in a recurring series\n * (e.g. an upstream calendar reports one occurrence as cancelled).\n * Internally this is translated into an addition to the parent\n * schedule's `recurrenceExdates`; no occurrence schedule row is\n * persisted for the cancelled date. For seeding the full exception\n * list on the master at initial sync, use `NewSchedule.recurrenceExdates`\n * instead.\n *\n * Use a normal occurrence record (without `cancelled`) for genuine\n * overrides — time changes, RSVP differences, etc.\n */\nexport type NewScheduleOccurrence = Pick<\n ScheduleOccurrence,\n \"occurrence\" | \"start\"\n> &\n Partial<\n Omit<ScheduleOccurrence, \"occurrence\" | \"start\" | \"schedule\" | \"tags\">\n > & {\n /** Tags for this occurrence */\n tags?: NewTags;\n\n /** Add or remove the twist's tags on this occurrence */\n twistTags?: Partial<Record<Tag, boolean>>;\n\n /** Whether this occurrence should be marked as unread */\n unread?: boolean;\n\n /** Contacts to upsert on this occurrence's schedule */\n contacts?: NewScheduleContact[];\n\n /**\n * Mark this single date as cancelled. The runtime translates this\n * into an addition to the parent schedule's `recurrenceExdates` and\n * archives any pre-existing override row for the same date — no\n * occurrence schedule row is created.\n */\n cancelled?: boolean;\n };\n\n/**\n * Type for updating schedule occurrences inline.\n */\nexport type ScheduleOccurrenceUpdate = Pick<\n NewScheduleOccurrence,\n \"occurrence\"\n> &\n Partial<Omit<NewScheduleOccurrence, \"occurrence\" | \"schedule\">>;\n";
8
8
  //# sourceMappingURL=schedule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../src/llm-docs/schedule.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAe,y0OAAy0O,CAAC"}
1
+ {"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../src/llm-docs/schedule.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAe,s0OAAs0O,CAAC"}
@@ -4,6 +4,6 @@
4
4
  * This file is auto-generated during build. Do not edit manually.
5
5
  * Generated from: prebuild.ts
6
6
  */
7
- declare const _default: "/**\n * Thread tags. Three types:\n * 1. Special tags, which trigger other behaviors\n * 2. Toggle tags, which anyone can toggle a shared value on or off\n * 3. Count tags, where everyone can add or remove their own\n */\nexport enum Tag {\n // Special tags\n Todo = 1,\n Done = 3,\n\n // Toggle tags\n Pinned = 100,\n Urgent = 101,\n Goal = 103,\n Decision = 104,\n Waiting = 105,\n Blocked = 106,\n Warning = 107,\n Question = 108,\n Twist = 109,\n Star = 110,\n Idea = 111,\n\n // Count tags\n Yes = 1000,\n No = 1001,\n Volunteer = 1002,\n Tada = 1003,\n Fire = 1004,\n Totally = 1005,\n Looking = 1006,\n Love = 1007,\n Rocket = 1008,\n Sparkles = 1009,\n Thanks = 1010,\n Smile = 1011,\n Wave = 1012,\n Praise = 1015,\n Applause = 1016,\n Cool = 1017,\n Sad = 1018,\n Reply = 1019,\n Thinking = 1013,\n Remember = 1014,\n Agreed = 1020,\n Relieved = 1021,\n Send = 1022,\n Noted = 1023,\n Laugh = 1024,\n Surprised = 1025,\n Confused = 1026,\n Dismayed = 1027,\n}\n";
7
+ declare const _default: "/**\n * Compute tags \u2014 system state the runtime auto-manages on threads and\n * notes (`todo`, `done`, `twist` activity marker, \u2026).\n *\n * The toggle range (100\u2013999) and count range (1000\u20131027) have been\n * retired in favour of the open Unicode emoji `Reaction` type \u2014 see\n * `@plotday/twister/plot`'s `Reactions` / `NewReactions` and the\n * per-row `note.reactions` / `thread.reactions` fields. Connectors\n * route emoji reactions through `reactions`, not `tags`.\n *\n * `Tag.Twist` is the surviving non-trivial tag: a system marker the\n * runtime adds to a note while a twist is processing it, and clears\n * once the twist returns. It's not user-facing and not a reaction.\n */\nexport enum Tag {\n Todo = 1,\n Done = 3,\n /** System marker for \"a twist is processing this note.\" Set by the\n * runtime when a twist callback fires, cleared on return. Twists\n * may still write `{ [Tag.Twist]: true | false }` to twistTags to\n * mark/unmark a note explicitly. */\n Twist = 12,\n}\n";
8
8
  export default _default;
9
9
  //# sourceMappingURL=tag.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../src/llm-docs/tag.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;wBAEY,y/BAAy/B;AAAxgC,wBAAygC"}
1
+ {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../src/llm-docs/tag.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;wBAEY,ugCAA8+B;AAA7/B,wBAA8/B"}
@@ -4,5 +4,5 @@
4
4
  * This file is auto-generated during build. Do not edit manually.
5
5
  * Generated from: prebuild.ts
6
6
  */
7
- export default "/**\n * Thread tags. Three types:\n * 1. Special tags, which trigger other behaviors\n * 2. Toggle tags, which anyone can toggle a shared value on or off\n * 3. Count tags, where everyone can add or remove their own\n */\nexport enum Tag {\n // Special tags\n Todo = 1,\n Done = 3,\n\n // Toggle tags\n Pinned = 100,\n Urgent = 101,\n Goal = 103,\n Decision = 104,\n Waiting = 105,\n Blocked = 106,\n Warning = 107,\n Question = 108,\n Twist = 109,\n Star = 110,\n Idea = 111,\n\n // Count tags\n Yes = 1000,\n No = 1001,\n Volunteer = 1002,\n Tada = 1003,\n Fire = 1004,\n Totally = 1005,\n Looking = 1006,\n Love = 1007,\n Rocket = 1008,\n Sparkles = 1009,\n Thanks = 1010,\n Smile = 1011,\n Wave = 1012,\n Praise = 1015,\n Applause = 1016,\n Cool = 1017,\n Sad = 1018,\n Reply = 1019,\n Thinking = 1013,\n Remember = 1014,\n Agreed = 1020,\n Relieved = 1021,\n Send = 1022,\n Noted = 1023,\n Laugh = 1024,\n Surprised = 1025,\n Confused = 1026,\n Dismayed = 1027,\n}\n";
7
+ export default "/**\n * Compute tags system state the runtime auto-manages on threads and\n * notes (`todo`, `done`, `twist` activity marker, …).\n *\n * The toggle range (100–999) and count range (1000–1027) have been\n * retired in favour of the open Unicode emoji `Reaction` type — see\n * `@plotday/twister/plot`'s `Reactions` / `NewReactions` and the\n * per-row `note.reactions` / `thread.reactions` fields. Connectors\n * route emoji reactions through `reactions`, not `tags`.\n *\n * `Tag.Twist` is the surviving non-trivial tag: a system marker the\n * runtime adds to a note while a twist is processing it, and clears\n * once the twist returns. It's not user-facing and not a reaction.\n */\nexport enum Tag {\n Todo = 1,\n Done = 3,\n /** System marker for \"a twist is processing this note.\" Set by the\n * runtime when a twist callback fires, cleared on return. Twists\n * may still write `{ [Tag.Twist]: true | false }` to twistTags to\n * mark/unmark a note explicitly. */\n Twist = 12,\n}\n";
8
8
  //# sourceMappingURL=tag.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tag.js","sourceRoot":"","sources":["../../src/llm-docs/tag.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAe,y/BAAy/B,CAAC"}
1
+ {"version":3,"file":"tag.js","sourceRoot":"","sources":["../../src/llm-docs/tag.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAe,8+BAA8+B,CAAC"}
@@ -4,6 +4,6 @@
4
4
  * This file is auto-generated during build. Do not edit manually.
5
5
  * Generated from: prebuild.ts
6
6
  */
7
- declare const _default: "import type { Static, TSchema } from \"typebox\";\n\nimport { ITool } from \"..\";\n\n/**\n * Built-in tool for prompting Large Language Models (LLMs).\n *\n * The AI tool provides twists and tools with access to LLM capabilities\n * for natural language processing, text generation, data extraction,\n * and intelligent decision making within their workflows.\n *\n * **Features:**\n * - Access to multiple AI providers (OpenAI, Anthropic, Google, Workers AI)\n * - Multi-turn conversation support with `messages`\n * - Tool calling with automatic execution\n * - Structured output with Typebox schemas via `outputSchema`\n * - Unified API across all models via Vercel AI SDK\n * - Automatic response parsing and validation with full type inference\n *\n * @example\n * ```typescript\n * import { Type } from \"typebox\";\n *\n * class SmartEmailTool extends Tool {\n * private ai: AI;\n *\n * constructor(id: string, tools: ToolBuilder) {\n * super();\n * this.ai = tools.get(AI);\n * }\n *\n * async categorizeEmail(emailContent: string) {\n * // Define the output schema using Typebox\n * const schema = Type.Object({\n * category: Type.Union([\n * Type.Literal(\"work\"),\n * Type.Literal(\"personal\"),\n * Type.Literal(\"spam\"),\n * Type.Literal(\"promotional\")\n * ]),\n * confidence: Type.Number({ minimum: 0, maximum: 1 }),\n * reasoning: Type.Optional(Type.String())\n * });\n *\n * const response = await this.ai.prompt({\n * model: { speed: \"fast\", cost: \"medium\" },\n * system: \"Classify emails into categories: work, personal, spam, or promotional.\",\n * prompt: `Categorize this email: ${emailContent}`,\n * outputSchema: schema\n * });\n *\n * return response.output;\n * }\n *\n * async generateResponse(emailContent: string) {\n * const response = await this.ai.prompt({\n * model: { speed: \"fast\", cost: \"medium\" },\n * system: \"Generate professional email responses that are helpful and concise.\",\n * prompt: `Write a response to: ${emailContent}`\n * });\n *\n * return response.text;\n * }\n * }\n * ```\n */\nexport abstract class AI extends ITool {\n /**\n * Returns which AI capabilities are currently available.\n * Check this before calling prompt() or embed() to gracefully\n * handle cases where AI is disabled by the user.\n */\n abstract available(): AICapabilities;\n\n /**\n * Sends a request to an AI model and returns the response using the Vercel AI SDK.\n *\n * Supports text generation, multi-turn conversations, structured outputs,\n * and tool calling across multiple AI providers via Cloudflare AI Gateway.\n *\n * @param request - AI request with model, prompt/messages, and optional configuration\n * @returns Promise resolving to the AI response with generated text and metadata\n *\n * @example\n * ```typescript\n * // Simple text generation\n * const response = await ai.prompt({\n * model: { speed: \"fast\", cost: \"medium\" },\n * prompt: \"Explain quantum computing in simple terms\"\n * });\n * console.log(response.text);\n *\n * // Fast and cheap for simple tasks\n * const response = await ai.prompt({\n * model: { speed: \"fast\", cost: \"low\" },\n * prompt: \"Summarize this text...\"\n * });\n * console.log(response.text);\n *\n * // With system instructions for complex reasoning\n * const response = await ai.prompt({\n * model: { speed: \"capable\", cost: \"high\" },\n * system: \"You are a helpful physics tutor.\",\n * prompt: \"Explain quantum entanglement\"\n * });\n * console.log(response.text);\n *\n * // Multi-turn conversation\n * const response = await ai.prompt({\n * model: { speed: \"balanced\", cost: \"medium\" },\n * messages: [\n * { role: \"user\", content: \"What is 2+2?\" },\n * { role: \"assistant\", content: \"2+2 equals 4.\" },\n * { role: \"user\", content: \"What about 3+3?\" }\n * ]\n * });\n * console.log(response.text);\n *\n * // Structured output with Typebox schema\n * const response = await ai.prompt({\n * model: { speed: \"fast\", cost: \"medium\" },\n * prompt: \"Extract information: John is 30 years old\",\n * outputSchema: Type.Object({\n * name: Type.String(),\n * age: Type.Number()\n * })\n * });\n * console.log(response.output); // { name: \"John\", age: 30 }\n *\n * // Tool calling\n * const response = await ai.prompt({\n * model: { speed: \"balanced\", cost: \"medium\" },\n * prompt: \"What's the weather in San Francisco?\",\n * tools: {\n * getWeather: {\n * description: \"Get weather for a city\",\n * parameters: Type.Object({\n * city: Type.String()\n * }),\n * execute: async ({ city }) => {\n * return { temp: 72, condition: \"sunny\" };\n * }\n * }\n * }\n * });\n * console.log(response.text); // Model's response using tool results\n * console.log(response.toolCalls); // Array of tool calls made\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract prompt<TOOLS extends AIToolSet, SCHEMA extends TSchema = never>(\n request: AIRequest<TOOLS, SCHEMA>\n ): Promise<AIResponse<TOOLS, SCHEMA>>;\n}\n\n/** Options for configuring AI tool usage in a twist. */\nexport type AIOptions = {\n /** Whether AI is required for this twist to function. Default: true */\n required?: boolean;\n};\n\n/** Describes which AI capabilities are currently available to this twist. */\nexport type AICapabilities = {\n /** Whether AI prompting (text generation) is available. */\n prompt: boolean;\n /** Whether AI embedding generation is available. */\n embed: boolean;\n};\n\n/**\n * Model preferences for selecting an AI model based on performance and cost requirements.\n * This allows Plot to match those preferences with user preferences (such as preferred or\n * disallowed providers), as well as availability of newer and better models.\n *\n * @example\n * ```typescript\n * // Fast and cheap - uses Workers AI models like Llama 3.2 1B\n * const response = await ai.prompt({\n * model: { speed: \"fast\", cost: \"low\" },\n * prompt: \"Summarize this in one sentence: ...\"\n * });\n *\n * // Balanced performance - uses GPT-5 Mini or Gemini 2.5 Flash\n * const response = await ai.prompt({\n * model: { speed: \"balanced\", cost: \"medium\" },\n * prompt: \"Analyze this data...\"\n * });\n *\n * // Most capable - uses Claude Sonnet 4.5 or Opus 4.1\n * const response = await ai.prompt({\n * model: { speed: \"capable\", cost: \"high\" },\n * prompt: \"Solve this complex reasoning problem...\"\n * });\n *\n * // Request a specific model with a hint\n * const response = await ai.prompt({\n * model: { speed: \"balanced\", cost: \"medium\", hint: AIModel.CLAUDE_SONNET_45 },\n * prompt: \"...\"\n * });\n * ```\n */\nexport type ModelPreferences = {\n /**\n * Desired speed tier:\n * - \"fast\": Optimized for low latency and quick responses\n * - \"balanced\": Good balance of speed and capability\n * - \"capable\": Maximum reasoning and problem-solving ability\n */\n speed: \"fast\" | \"balanced\" | \"capable\";\n\n /**\n * Desired cost tier:\n * - \"low\": Minimal cost, often using Workers AI models (free/very cheap)\n * - \"medium\": Moderate pricing for good performance\n * - \"high\": Premium pricing for best-in-class models\n */\n cost: \"low\" | \"medium\" | \"high\";\n\n /**\n * Optional hint to suggest a specific model. The system will use this\n * model if possible, but may override it based on user preferences.\n */\n hint?: AIModel;\n};\n\n/**\n * Supported AI models available through Cloudflare AI Gateway and Workers AI.\n *\n * Models are organized by provider:\n * - **OpenAI**: Latest GPT models via AI Gateway\n * - **Anthropic**: Claude models via AI Gateway (prefix with \"anthropic/\")\n * - **Google**: Gemini models via AI Gateway (prefix with \"google-ai-studio/\")\n * - **Workers AI**: Models running on Cloudflare's network (free/low cost)\n */\nexport enum AIModel {\n // OpenAI models - Latest GPT and reasoning models\n GPT_5 = \"openai/gpt-5\",\n GPT_5_PRO = \"openai/gpt-5-pro\",\n GPT_5_MINI = \"openai/gpt-5-mini\",\n GPT_5_NANO = \"openai/gpt-5-nano\",\n GPT_4O = \"openai/gpt-4o\",\n GPT_4O_MINI = \"openai/gpt-4o-mini\",\n O3 = \"openai/o3\",\n O3_MINI = \"openai/o3-mini\",\n\n // Anthropic models - Claude 4.x series\n CLAUDE_OPUS_46 = \"anthropic/claude-opus-4-6\",\n CLAUDE_SONNET_46 = \"anthropic/claude-sonnet-4-6\",\n CLAUDE_HAIKU_45 = \"anthropic/claude-haiku-4-5\",\n\n // Google models - Gemini 2.x series\n GEMINI_25_PRO = \"google/gemini-2.5-pro\",\n GEMINI_25_FLASH = \"google/gemini-2.5-flash\",\n GEMINI_25_FLASH_LITE = \"google/gemini-2.5-flash-lite\",\n GEMINI_20_FLASH = \"google/gemini-2.0-flash\",\n GEMINI_20_FLASH_LITE = \"google/gemini-2.0-flash-lite\",\n\n // Cloudflare Workers AI models - Free/low-cost models running on Cloudflare's network\n LLAMA_4_SCOUT_17B = \"meta/llama-4-scout-17b-16e-instruct\",\n LLAMA_33_70B = \"meta/llama-3.3-70b-instruct-fp8-fast\",\n LLAMA_31_8B = \"meta/llama-3.1-8b-instruct-fp8\",\n LLAMA_32_1B = \"meta/llama-3.2-1b-instruct\",\n DEEPSEEK_R1_32B = \"deepseek-ai/deepseek-r1-distill-qwen-32b\",\n}\n\n/**\n * Request parameters for AI text generation, matching Vercel AI SDK's generateText() function.\n */\nexport interface AIRequest<\n TOOLS extends AIToolSet,\n SCHEMA extends TSchema = never\n> {\n /**\n * Model selection preferences based on desired speed and cost characteristics.\n * Plot will automatically select the best available model matching these preferences.\n *\n * @example\n * // Fast and cheap - good for simple tasks\n * model: { speed: \"fast\", cost: \"low\" }\n *\n * @example\n * // Balanced performance - general purpose\n * model: { speed: \"balanced\", cost: \"medium\" }\n *\n * @example\n * // Maximum capability - complex reasoning\n * model: { speed: \"capable\", cost: \"high\" }\n *\n * @example\n * // With a specific model hint\n * model: { speed: \"balanced\", cost: \"medium\", hint: \"anthropic/claude-sonnet-4-6\" }\n */\n model: ModelPreferences;\n\n /**\n * System instructions to guide the model's behavior.\n */\n system?: string;\n\n /**\n * The user's input prompt. Can be a simple string or an array of messages for multi-turn conversations.\n */\n prompt?: string;\n\n /**\n * Conversation messages for multi-turn interactions.\n * Replaces 'prompt' for more complex conversations.\n */\n messages?: AIMessage[];\n\n /**\n * Tools that the model can call during generation.\n * Each tool definition includes a description, input schema, and optional execute function.\n */\n tools?: TOOLS;\n\n /**\n * Controls which tools the model can use.\n * - \"auto\": Model decides whether to use tools\n * - \"none\": Model cannot use tools\n * - \"required\": Model must use at least one tool\n * - { type: \"tool\", toolName: string }: Model must use specific tool\n */\n toolChoice?: ToolChoice<TOOLS>;\n\n /**\n * Structured output schema using Typebox.\n * Typebox schemas are JSON Schema objects that provide full TypeScript type inference.\n */\n outputSchema?: SCHEMA;\n\n /**\n * Maximum number of tokens to generate.\n */\n maxOutputTokens?: number;\n\n /**\n * Temperature for controlling randomness (0-2).\n * Higher values make output more random, lower values more deterministic.\n */\n temperature?: number;\n\n /**\n * Top P sampling parameter (0-1).\n * Controls diversity by limiting to top probability tokens.\n */\n topP?: number;\n}\n\n/**\n * Response from AI text generation, matching Vercel AI SDK's GenerateTextResult.\n */\nexport interface AIResponse<\n TOOLS extends AIToolSet,\n SCHEMA extends TSchema = never\n> {\n /**\n * The generated text.\n */\n text: string;\n\n /**\n * Tool calls made by the model during generation.\n */\n toolCalls?: ToolCallArray<TOOLS>;\n\n /**\n * Results from tool executions.\n */\n toolResults?: ToolResultArray<TOOLS>;\n\n /**\n * Reason why the model stopped generating.\n */\n finishReason:\n | \"stop\"\n | \"length\"\n | \"content-filter\"\n | \"tool-calls\"\n | \"error\"\n | \"other\"\n | \"unknown\";\n\n /**\n * Token usage information for this generation.\n */\n usage: AIUsage;\n\n /**\n * Sources used by the model (if supported).\n */\n sources?: Array<AISource>;\n\n /**\n * Structured output when using outputSchema.\n * Type is automatically inferred from the Typebox schema.\n */\n output?: Static<SCHEMA>;\n\n /**\n * Response metadata including messages.\n */\n response?: {\n id?: string;\n timestamp?: Date;\n modelId?: string;\n messages?: AIMessage[];\n };\n}\n\n// ============================================================================\n// Message Types\n// ============================================================================\n\n/**\n * A system message. It can contain system information.\n *\n * Note: using the \"system\" part of the prompt is strongly preferred\n * to increase the resilience against prompt injection attacks,\n * and because not all providers support several system messages.\n */\nexport type AISystemMessage = {\n role: \"system\";\n content: string;\n};\n\n/**\n * A user message. It can contain text or a combination of text and images.\n */\nexport type AIUserMessage = {\n role: \"user\";\n content: string | Array<TextPart | ImagePart | FilePart>;\n};\n\n/**\n * An assistant message. It can contain text, tool calls, or a combination of text and tool calls.\n */\nexport type AIAssistantMessage = {\n role: \"assistant\";\n content:\n | string\n | Array<\n TextPart | FilePart | ReasoningPart | ToolCallPart | ToolResultPart\n >;\n};\n\n/**\n * A tool message. It contains the result of one or more tool calls.\n */\nexport type AIToolMessage = {\n role: \"tool\";\n content: Array<ToolResultPart>;\n};\n\n/**\n * A message that can be used in the `messages` field of a prompt.\n * It can be a user message, an assistant message, or a tool message.\n */\nexport type AIMessage =\n | AISystemMessage\n | AIUserMessage\n | AIAssistantMessage\n | AIToolMessage;\n\n// ============================================================================\n// Usage & Sources\n// ============================================================================\n\n/**\n * Represents the number of tokens used in a prompt and completion.\n */\nexport type AIUsage = {\n /**\n * The number of tokens used in the prompt.\n */\n inputTokens?: number;\n /**\n * The number of tokens used in the completion.\n */\n outputTokens?: number;\n /**\n * The total number of tokens used (promptTokens + completionTokens).\n */\n totalTokens?: number;\n /**\n * The number of reasoning tokens used in the completion.\n */\n reasoningTokens?: number;\n};\n\n/**\n * A source that has been used as input to generate the response.\n */\nexport type AISource =\n | {\n type: \"source\";\n /**\n * A URL source. This is returned by web search RAG models.\n */\n sourceType: \"url\";\n /**\n * The ID of the source.\n */\n id: string;\n /**\n * The URL of the source.\n */\n url: string;\n /**\n * The title of the source.\n */\n title?: string;\n }\n | {\n type: \"source\";\n /**\n * The type of source - document sources reference files/documents.\n */\n sourceType: \"document\";\n /**\n * The ID of the source.\n */\n id: string;\n /**\n * IANA media type of the document (e.g., 'application/pdf').\n */\n mediaType: string;\n /**\n * The title of the document.\n */\n title: string;\n /**\n * Optional filename of the document.\n */\n filename?: string;\n };\n\n// ============================================================================\n// Content Parts\n// ============================================================================\n\n/**\n * Text content part of a prompt. It contains a string of text.\n */\nexport interface TextPart {\n type: \"text\";\n /**\n * The text content.\n */\n text: string;\n}\n\n/**\n * Data content. Can either be a base64-encoded string, a Uint8Array, or an ArrayBuffer.\n */\nexport type DataContent = string | Uint8Array | ArrayBuffer;\n\n/**\n * Image content part of a prompt. It contains an image.\n */\nexport interface ImagePart {\n type: \"image\";\n /**\n * Image data. Can either be:\n *\n * - data: a base64-encoded string, a Uint8Array, an ArrayBuffer, or a Buffer\n * - URL: a URL that points to the image\n */\n image: DataContent | URL;\n /**\n * Optional mime type of the image.\n */\n mimeType?: string;\n}\n\n/**\n * File content part of a prompt. It contains a file.\n */\nexport interface FilePart {\n type: \"file\";\n /**\n * File data. Can either be:\n *\n * - data: a base64-encoded string, a Uint8Array, an ArrayBuffer, or a Buffer\n * - URL: a URL that points to the file\n */\n data: DataContent | URL;\n /**\n * Optional filename of the file.\n */\n filename?: string;\n /**\n * IANA media type of the file.\n *\n * @see https://www.iana.org/assignments/media-types/media-types.xhtml\n */\n mediaType: string;\n}\n\n/**\n * Reasoning content part of a prompt. It contains a reasoning.\n */\nexport interface ReasoningPart {\n type: \"reasoning\";\n /**\n * The reasoning text.\n */\n text: string;\n /**\n * An optional signature for verifying that the reasoning originated from the model.\n */\n signature?: string;\n}\n\n/**\n * Redacted reasoning content part of a prompt.\n */\nexport interface RedactedReasoningPart {\n type: \"redacted-reasoning\";\n /**\n * Redacted reasoning data.\n */\n data: string;\n}\n\n/**\n * Tool call content part of a prompt. It contains a tool call (usually generated by the AI model).\n */\nexport interface ToolCallPart {\n type: \"tool-call\";\n /**\n * ID of the tool call. This ID is used to match the tool call with the tool result.\n */\n toolCallId: string;\n /**\n * Name of the tool that is being called.\n */\n toolName: string;\n /**\n * Arguments of the tool call. This is a JSON-serializable object that matches the tool's input schema.\n */\n input: unknown;\n}\n\ntype JSONValue = null | string | number | boolean | JSONObject | JSONArray;\ntype JSONObject = {\n [key: string]: JSONValue;\n};\ntype JSONArray = JSONValue[];\n\n/**\n * Tool result content part of a prompt. It contains the result of the tool call with the matching ID.\n */\nexport interface ToolResultPart {\n type: \"tool-result\";\n /**\n * ID of the tool call that this result is associated with.\n */\n toolCallId: string;\n /**\n * Name of the tool that generated this result.\n */\n toolName: string;\n /**\n * Result of the tool call. This is a JSON-serializable object.\n */\n output:\n | {\n type: \"text\";\n value: string;\n }\n | {\n type: \"json\";\n value: JSONValue;\n }\n | {\n type: \"error-text\";\n value: string;\n }\n | {\n type: \"error-json\";\n value: JSONValue;\n }\n | {\n type: \"content\";\n value: Array<\n | {\n type: \"text\";\n /**\nText content.\n*/\n text: string;\n }\n | {\n type: \"media\";\n /**\nBase-64 encoded media data.\n*/\n data: string;\n /**\nIANA media type.\n@see https://www.iana.org/assignments/media-types/media-types.xhtml\n*/\n mediaType: string;\n }\n >;\n };\n}\n\n// ============================================================================\n// Tool Types\n// ============================================================================\n\ntype ToolParameters = TSchema;\n\ntype inferParameters<PARAMETERS extends ToolParameters> = Static<PARAMETERS>;\n\n/**\n * Options passed to tool execution functions.\n */\nexport interface ToolExecutionOptions {\n /**\n * The ID of the tool call. You can use it e.g. when sending tool-call related information with stream data.\n */\n toolCallId: string;\n /**\n * Messages that were sent to the language model to initiate the response that contained the tool call.\n * The messages **do not** include the system prompt nor the assistant response that contained the tool call.\n */\n messages: AIMessage[];\n /**\n * An optional abort signal that indicates that the overall operation should be aborted.\n */\n abortSignal?: AbortSignal;\n}\n\n/**\n * A tool contains the description and the schema of the input that the tool expects.\n * This enables the language model to generate the input.\n *\n * The tool can also contain an optional execute function for the actual execution function of the tool.\n */\nexport type AITool<PARAMETERS extends ToolParameters = any, RESULT = any> = {\n /**\n * The schema of the input that the tool expects. The language model will use this to generate the input.\n * It is also used to validate the output of the language model.\n * Use descriptions to make the input understandable for the language model.\n */\n parameters: PARAMETERS;\n /**\n * The schema of the input that the tool expects. The language model will use this to generate the input.\n * It is also used to validate the output of the language model.\n * Use descriptions to make the input understandable for the language model.\n */\n inputSchema: TSchema;\n /**\n * An optional description of what the tool does.\n * Will be used by the language model to decide whether to use the tool.\n * Not used for provider-defined tools.\n */\n description?: string;\n /**\n * An async function that is called with the arguments from the tool call and produces a result.\n * If not provided, the tool will not be executed automatically.\n *\n * @param args - The input of the tool call\n * @param options - Execution options including abort signal and messages\n */\n execute?: (\n args: inferParameters<PARAMETERS>,\n options: ToolExecutionOptions\n ) => PromiseLike<RESULT>;\n} & (\n | {\n /**\n * Function tool.\n */\n type?: undefined | \"function\";\n }\n | {\n /**\n * Provider-defined tool.\n */\n type: \"provider-defined\";\n /**\n * The ID of the tool. Should follow the format `<provider-name>.<tool-name>`.\n */\n id: `${string}.${string}`;\n /**\n * The arguments for configuring the tool. Must match the expected arguments defined by the provider for this tool.\n */\n args: Record<string, unknown>;\n }\n);\n\n/**\n * Tool choice for the generation. It supports the following settings:\n *\n * - `auto` (default): the model can choose whether and which tools to call.\n * - `required`: the model must call a tool. It can choose which tool to call.\n * - `none`: the model must not call tools\n * - `{ type: 'tool', toolName: string (typed) }`: the model must call the specified tool\n */\ntype ToolChoice<TOOLS extends Record<string, unknown>> =\n | \"auto\"\n | \"none\"\n | \"required\"\n | {\n type: \"tool\";\n toolName: Extract<keyof TOOLS, string>;\n };\n\nexport type AIToolSet = Record<\n string,\n (\n | AITool<never, never>\n | AITool<any, any>\n | AITool<any, never>\n | AITool<never, any>\n ) &\n Pick<AITool<any, any>, \"execute\">\n>;\n\n// ============================================================================\n// Internal Helper Types\n// ============================================================================\n\ntype ToolCallUnion<_TOOLS extends AIToolSet> = {\n type: \"tool-call\";\n toolCallId: string;\n toolName: string;\n args?: unknown;\n};\n\ntype ToolCallArray<TOOLS extends AIToolSet> = Array<ToolCallUnion<TOOLS>>;\n\ntype ToolResultUnion<_TOOLS extends AIToolSet> = {\n type: \"tool-result\";\n toolCallId: string;\n toolName: string;\n args?: unknown;\n result?: unknown;\n};\n\ntype ToolResultArray<TOOLS extends AIToolSet> = Array<ToolResultUnion<TOOLS>>;\n";
7
+ declare const _default: "import type { Static, TSchema } from \"typebox\";\n\nimport { ITool } from \"..\";\n\n/**\n * Built-in tool for prompting Large Language Models (LLMs).\n *\n * The AI tool provides twists and tools with access to LLM capabilities\n * for natural language processing, text generation, data extraction,\n * and intelligent decision making within their workflows.\n *\n * **Features:**\n * - Access to multiple AI providers (OpenAI, Anthropic, Google, Workers AI)\n * - Multi-turn conversation support with `messages`\n * - Tool calling with automatic execution\n * - Structured output with Typebox schemas via `outputSchema`\n * - Unified API across all models via Vercel AI SDK\n * - Automatic response parsing and validation with full type inference\n *\n * @example\n * ```typescript\n * import { Type } from \"typebox\";\n *\n * class SmartEmailTool extends Tool {\n * private ai: AI;\n *\n * constructor(id: string, tools: ToolBuilder) {\n * super();\n * this.ai = tools.get(AI);\n * }\n *\n * async categorizeEmail(emailContent: string) {\n * // Define the output schema using Typebox\n * const schema = Type.Object({\n * category: Type.Union([\n * Type.Literal(\"work\"),\n * Type.Literal(\"personal\"),\n * Type.Literal(\"spam\"),\n * Type.Literal(\"promotional\")\n * ]),\n * confidence: Type.Number({ minimum: 0, maximum: 1 }),\n * reasoning: Type.Optional(Type.String())\n * });\n *\n * const response = await this.ai.prompt({\n * model: { speed: \"fast\", cost: \"medium\" },\n * system: \"Classify emails into categories: work, personal, spam, or promotional.\",\n * prompt: `Categorize this email: ${emailContent}`,\n * outputSchema: schema\n * });\n *\n * return response.output;\n * }\n *\n * async generateResponse(emailContent: string) {\n * const response = await this.ai.prompt({\n * model: { speed: \"fast\", cost: \"medium\" },\n * system: \"Generate professional email responses that are helpful and concise.\",\n * prompt: `Write a response to: ${emailContent}`\n * });\n *\n * return response.text;\n * }\n * }\n * ```\n */\nexport abstract class AI extends ITool {\n /**\n * Returns which AI capabilities are currently available.\n * Check this before calling prompt() or embed() to gracefully\n * handle cases where AI is disabled by the user.\n *\n * Built-in tools are accessed as RPC stubs, so from a twist this call\n * resolves asynchronously \u2014 always `await` it.\n */\n abstract available(): AICapabilities | Promise<AICapabilities>;\n\n /**\n * Sends a request to an AI model and returns the response using the Vercel AI SDK.\n *\n * Supports text generation, multi-turn conversations, structured outputs,\n * and tool calling across multiple AI providers via Cloudflare AI Gateway.\n *\n * @param request - AI request with model, prompt/messages, and optional configuration\n * @returns Promise resolving to the AI response with generated text and metadata\n *\n * @example\n * ```typescript\n * // Simple text generation\n * const response = await ai.prompt({\n * model: { speed: \"fast\", cost: \"medium\" },\n * prompt: \"Explain quantum computing in simple terms\"\n * });\n * console.log(response.text);\n *\n * // Fast and cheap for simple tasks\n * const response = await ai.prompt({\n * model: { speed: \"fast\", cost: \"low\" },\n * prompt: \"Summarize this text...\"\n * });\n * console.log(response.text);\n *\n * // With system instructions for complex reasoning\n * const response = await ai.prompt({\n * model: { speed: \"capable\", cost: \"high\" },\n * system: \"You are a helpful physics tutor.\",\n * prompt: \"Explain quantum entanglement\"\n * });\n * console.log(response.text);\n *\n * // Multi-turn conversation\n * const response = await ai.prompt({\n * model: { speed: \"balanced\", cost: \"medium\" },\n * messages: [\n * { role: \"user\", content: \"What is 2+2?\" },\n * { role: \"assistant\", content: \"2+2 equals 4.\" },\n * { role: \"user\", content: \"What about 3+3?\" }\n * ]\n * });\n * console.log(response.text);\n *\n * // Structured output with Typebox schema\n * const response = await ai.prompt({\n * model: { speed: \"fast\", cost: \"medium\" },\n * prompt: \"Extract information: John is 30 years old\",\n * outputSchema: Type.Object({\n * name: Type.String(),\n * age: Type.Number()\n * })\n * });\n * console.log(response.output); // { name: \"John\", age: 30 }\n *\n * // Tool calling\n * const response = await ai.prompt({\n * model: { speed: \"balanced\", cost: \"medium\" },\n * prompt: \"What's the weather in San Francisco?\",\n * tools: {\n * getWeather: {\n * description: \"Get weather for a city\",\n * inputSchema: Type.Object({\n * city: Type.String()\n * }),\n * execute: async ({ city }) => {\n * return { temp: 72, condition: \"sunny\" };\n * }\n * }\n * }\n * });\n * console.log(response.text); // Model's response using tool results\n * console.log(response.toolCalls); // Array of tool calls made\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n abstract prompt<TOOLS extends AIToolSet, SCHEMA extends TSchema = never>(\n request: AIRequest<TOOLS, SCHEMA>\n ): Promise<AIResponse<TOOLS, SCHEMA>>;\n}\n\n/** Options for configuring AI tool usage in a twist. */\nexport type AIOptions = {\n /** Whether AI is required for this twist to function. Default: true */\n required?: boolean;\n};\n\n/** Describes which AI capabilities are currently available to this twist. */\nexport type AICapabilities = {\n /** Whether AI prompting (text generation) is available. */\n prompt: boolean;\n /** Whether AI embedding generation is available. */\n embed: boolean;\n /**\n * Whether provider-native web search is available. True for Plot AI and\n * Anthropic/Google BYOK providers; false for OpenAI/custom BYOK providers\n * that don't expose a server-side web search tool through this runtime.\n */\n webSearch: boolean;\n};\n\n/**\n * Model preferences for selecting an AI model based on performance and cost requirements.\n * This allows Plot to match those preferences with user preferences (such as preferred or\n * disallowed providers), as well as availability of newer and better models.\n *\n * @example\n * ```typescript\n * // Fast and cheap - uses Workers AI models like Llama 3.2 1B\n * const response = await ai.prompt({\n * model: { speed: \"fast\", cost: \"low\" },\n * prompt: \"Summarize this in one sentence: ...\"\n * });\n *\n * // Balanced performance - uses GPT-5 Mini or Gemini 2.5 Flash\n * const response = await ai.prompt({\n * model: { speed: \"balanced\", cost: \"medium\" },\n * prompt: \"Analyze this data...\"\n * });\n *\n * // Most capable - uses Claude Sonnet 4.5 or Opus 4.1\n * const response = await ai.prompt({\n * model: { speed: \"capable\", cost: \"high\" },\n * prompt: \"Solve this complex reasoning problem...\"\n * });\n *\n * // Request a specific model with a hint\n * const response = await ai.prompt({\n * model: { speed: \"balanced\", cost: \"medium\", hint: AIModel.CLAUDE_SONNET_45 },\n * prompt: \"...\"\n * });\n * ```\n */\nexport type ModelPreferences = {\n /**\n * Desired speed tier:\n * - \"fast\": Optimized for low latency and quick responses\n * - \"balanced\": Good balance of speed and capability\n * - \"capable\": Maximum reasoning and problem-solving ability\n */\n speed: \"fast\" | \"balanced\" | \"capable\";\n\n /**\n * Desired cost tier:\n * - \"low\": Minimal cost, often using Workers AI models (free/very cheap)\n * - \"medium\": Moderate pricing for good performance\n * - \"high\": Premium pricing for best-in-class models\n */\n cost: \"low\" | \"medium\" | \"high\";\n\n /**\n * Optional hint to suggest a specific model. The system will use this\n * model if possible, but may override it based on user preferences.\n */\n hint?: AIModel;\n};\n\n/**\n * Supported AI models available through Cloudflare AI Gateway and Workers AI.\n *\n * Models are organized by provider:\n * - **OpenAI**: Latest GPT models via AI Gateway\n * - **Anthropic**: Claude models via AI Gateway (prefix with \"anthropic/\")\n * - **Google**: Gemini models via AI Gateway (prefix with \"google-ai-studio/\")\n * - **Workers AI**: Models running on Cloudflare's network (free/low cost)\n */\nexport enum AIModel {\n // OpenAI models - Latest GPT and reasoning models\n GPT_5 = \"openai/gpt-5\",\n GPT_5_PRO = \"openai/gpt-5-pro\",\n GPT_5_MINI = \"openai/gpt-5-mini\",\n GPT_5_NANO = \"openai/gpt-5-nano\",\n GPT_4O = \"openai/gpt-4o\",\n GPT_4O_MINI = \"openai/gpt-4o-mini\",\n O3 = \"openai/o3\",\n O3_MINI = \"openai/o3-mini\",\n\n // Anthropic models - Claude 4.x series\n CLAUDE_OPUS_46 = \"anthropic/claude-opus-4-6\",\n CLAUDE_SONNET_46 = \"anthropic/claude-sonnet-4-6\",\n CLAUDE_HAIKU_45 = \"anthropic/claude-haiku-4-5\",\n\n // Google models - Gemini 2.x series\n GEMINI_25_PRO = \"google/gemini-2.5-pro\",\n GEMINI_25_FLASH = \"google/gemini-2.5-flash\",\n GEMINI_25_FLASH_LITE = \"google/gemini-2.5-flash-lite\",\n GEMINI_20_FLASH = \"google/gemini-2.0-flash\",\n GEMINI_20_FLASH_LITE = \"google/gemini-2.0-flash-lite\",\n\n // Cloudflare Workers AI models - Free/low-cost models running on Cloudflare's network\n LLAMA_4_SCOUT_17B = \"meta/llama-4-scout-17b-16e-instruct\",\n LLAMA_33_70B = \"meta/llama-3.3-70b-instruct-fp8-fast\",\n LLAMA_31_8B = \"meta/llama-3.1-8b-instruct-fp8\",\n LLAMA_32_1B = \"meta/llama-3.2-1b-instruct\",\n DEEPSEEK_R1_32B = \"deepseek-ai/deepseek-r1-distill-qwen-32b\",\n}\n\n/**\n * Request parameters for AI text generation, matching Vercel AI SDK's generateText() function.\n */\nexport interface AIRequest<\n TOOLS extends AIToolSet,\n SCHEMA extends TSchema = never\n> {\n /**\n * Model selection preferences based on desired speed and cost characteristics.\n * Plot will automatically select the best available model matching these preferences.\n *\n * @example\n * // Fast and cheap - good for simple tasks\n * model: { speed: \"fast\", cost: \"low\" }\n *\n * @example\n * // Balanced performance - general purpose\n * model: { speed: \"balanced\", cost: \"medium\" }\n *\n * @example\n * // Maximum capability - complex reasoning\n * model: { speed: \"capable\", cost: \"high\" }\n *\n * @example\n * // With a specific model hint\n * model: { speed: \"balanced\", cost: \"medium\", hint: \"anthropic/claude-sonnet-4-6\" }\n */\n model: ModelPreferences;\n\n /**\n * System instructions to guide the model's behavior.\n */\n system?: string;\n\n /**\n * The user's input prompt. Can be a simple string or an array of messages for multi-turn conversations.\n */\n prompt?: string;\n\n /**\n * Conversation messages for multi-turn interactions.\n * Replaces 'prompt' for more complex conversations.\n */\n messages?: AIMessage[];\n\n /**\n * Tools that the model can call during generation.\n * Each tool definition includes a description, input schema, and optional execute function.\n */\n tools?: TOOLS;\n\n /**\n * Controls which tools the model can use.\n * - \"auto\": Model decides whether to use tools\n * - \"none\": Model cannot use tools\n * - \"required\": Model must use at least one tool\n * - { type: \"tool\", toolName: string }: Model must use specific tool\n */\n toolChoice?: ToolChoice<TOOLS>;\n\n /**\n * Structured output schema using Typebox.\n * Typebox schemas are JSON Schema objects that provide full TypeScript type inference.\n */\n outputSchema?: SCHEMA;\n\n /**\n * Maximum number of tokens to generate.\n */\n maxOutputTokens?: number;\n\n /**\n * Temperature for controlling randomness (0-2).\n * Higher values make output more random, lower values more deterministic.\n */\n temperature?: number;\n\n /**\n * Top P sampling parameter (0-1).\n * Controls diversity by limiting to top probability tokens.\n */\n topP?: number;\n\n /**\n * Enable provider-native web search so the model can retrieve\n * up-to-date information from the web. The search is executed\n * server-side by the provider and any pages used are returned in\n * {@link AIResponse.sources}.\n *\n * Only available on web-search-capable providers (Anthropic and\n * Google). Check {@link AICapabilities.webSearch} via `available()`\n * before relying on it; on unsupported providers the flag is ignored.\n *\n * Pass `true` for defaults, or an object to cap the number of searches.\n */\n webSearch?: boolean | { maxUses?: number };\n\n /**\n * Maximum number of sequential generation steps for agentic tool use.\n * When the model calls a tool, its result is fed back and the model is\n * called again, up to `maxSteps` times, until it produces a final answer.\n *\n * Defaults to 1 (single step \u2014 tool calls are returned but not looped),\n * preserving prior behavior. Set higher (e.g. 6) to let the model chain\n * tool calls into a final answer.\n */\n maxSteps?: number;\n}\n\n/**\n * Response from AI text generation, matching Vercel AI SDK's GenerateTextResult.\n */\nexport interface AIResponse<\n TOOLS extends AIToolSet,\n SCHEMA extends TSchema = never\n> {\n /**\n * The generated text.\n */\n text: string;\n\n /**\n * Tool calls made by the model during generation.\n */\n toolCalls?: ToolCallArray<TOOLS>;\n\n /**\n * Results from tool executions.\n */\n toolResults?: ToolResultArray<TOOLS>;\n\n /**\n * Reason why the model stopped generating.\n */\n finishReason:\n | \"stop\"\n | \"length\"\n | \"content-filter\"\n | \"tool-calls\"\n | \"error\"\n | \"other\"\n | \"unknown\";\n\n /**\n * Token usage information for this generation.\n */\n usage: AIUsage;\n\n /**\n * Sources used by the model (if supported).\n */\n sources?: Array<AISource>;\n\n /**\n * Structured output when using outputSchema.\n * Type is automatically inferred from the Typebox schema.\n */\n output?: Static<SCHEMA>;\n\n /**\n * Response metadata including messages.\n */\n response?: {\n id?: string;\n timestamp?: Date;\n modelId?: string;\n messages?: AIMessage[];\n };\n}\n\n// ============================================================================\n// Message Types\n// ============================================================================\n\n/**\n * A system message. It can contain system information.\n *\n * Note: using the \"system\" part of the prompt is strongly preferred\n * to increase the resilience against prompt injection attacks,\n * and because not all providers support several system messages.\n */\nexport type AISystemMessage = {\n role: \"system\";\n content: string;\n};\n\n/**\n * A user message. It can contain text or a combination of text and images.\n */\nexport type AIUserMessage = {\n role: \"user\";\n content: string | Array<TextPart | ImagePart | FilePart>;\n};\n\n/**\n * An assistant message. It can contain text, tool calls, or a combination of text and tool calls.\n */\nexport type AIAssistantMessage = {\n role: \"assistant\";\n content:\n | string\n | Array<\n TextPart | FilePart | ReasoningPart | ToolCallPart | ToolResultPart\n >;\n};\n\n/**\n * A tool message. It contains the result of one or more tool calls.\n */\nexport type AIToolMessage = {\n role: \"tool\";\n content: Array<ToolResultPart>;\n};\n\n/**\n * A message that can be used in the `messages` field of a prompt.\n * It can be a user message, an assistant message, or a tool message.\n */\nexport type AIMessage =\n | AISystemMessage\n | AIUserMessage\n | AIAssistantMessage\n | AIToolMessage;\n\n// ============================================================================\n// Usage & Sources\n// ============================================================================\n\n/**\n * Represents the number of tokens used in a prompt and completion.\n */\nexport type AIUsage = {\n /**\n * The number of tokens used in the prompt.\n */\n inputTokens?: number;\n /**\n * The number of tokens used in the completion.\n */\n outputTokens?: number;\n /**\n * The total number of tokens used (promptTokens + completionTokens).\n */\n totalTokens?: number;\n /**\n * The number of reasoning tokens used in the completion.\n */\n reasoningTokens?: number;\n};\n\n/**\n * A source that has been used as input to generate the response.\n */\nexport type AISource =\n | {\n type: \"source\";\n /**\n * A URL source. This is returned by web search RAG models.\n */\n sourceType: \"url\";\n /**\n * The ID of the source.\n */\n id: string;\n /**\n * The URL of the source.\n */\n url: string;\n /**\n * The title of the source.\n */\n title?: string;\n }\n | {\n type: \"source\";\n /**\n * The type of source - document sources reference files/documents.\n */\n sourceType: \"document\";\n /**\n * The ID of the source.\n */\n id: string;\n /**\n * IANA media type of the document (e.g., 'application/pdf').\n */\n mediaType: string;\n /**\n * The title of the document.\n */\n title: string;\n /**\n * Optional filename of the document.\n */\n filename?: string;\n };\n\n// ============================================================================\n// Content Parts\n// ============================================================================\n\n/**\n * Text content part of a prompt. It contains a string of text.\n */\nexport interface TextPart {\n type: \"text\";\n /**\n * The text content.\n */\n text: string;\n}\n\n/**\n * Data content. Can either be a base64-encoded string, a Uint8Array, or an ArrayBuffer.\n */\nexport type DataContent = string | Uint8Array | ArrayBuffer;\n\n/**\n * Image content part of a prompt. It contains an image.\n */\nexport interface ImagePart {\n type: \"image\";\n /**\n * Image data. Can either be:\n *\n * - data: a base64-encoded string, a Uint8Array, an ArrayBuffer, or a Buffer\n * - URL: a URL that points to the image\n */\n image: DataContent | URL;\n /**\n * Optional mime type of the image.\n */\n mimeType?: string;\n}\n\n/**\n * File content part of a prompt. It contains a file.\n */\nexport interface FilePart {\n type: \"file\";\n /**\n * File data. Can either be:\n *\n * - data: a base64-encoded string, a Uint8Array, an ArrayBuffer, or a Buffer\n * - URL: a URL that points to the file\n */\n data: DataContent | URL;\n /**\n * Optional filename of the file.\n */\n filename?: string;\n /**\n * IANA media type of the file.\n *\n * @see https://www.iana.org/assignments/media-types/media-types.xhtml\n */\n mediaType: string;\n}\n\n/**\n * Reasoning content part of a prompt. It contains a reasoning.\n */\nexport interface ReasoningPart {\n type: \"reasoning\";\n /**\n * The reasoning text.\n */\n text: string;\n /**\n * An optional signature for verifying that the reasoning originated from the model.\n */\n signature?: string;\n}\n\n/**\n * Redacted reasoning content part of a prompt.\n */\nexport interface RedactedReasoningPart {\n type: \"redacted-reasoning\";\n /**\n * Redacted reasoning data.\n */\n data: string;\n}\n\n/**\n * Tool call content part of a prompt. It contains a tool call (usually generated by the AI model).\n */\nexport interface ToolCallPart {\n type: \"tool-call\";\n /**\n * ID of the tool call. This ID is used to match the tool call with the tool result.\n */\n toolCallId: string;\n /**\n * Name of the tool that is being called.\n */\n toolName: string;\n /**\n * Arguments of the tool call. This is a JSON-serializable object that matches the tool's input schema.\n */\n input: unknown;\n}\n\ntype JSONValue = null | string | number | boolean | JSONObject | JSONArray;\ntype JSONObject = {\n [key: string]: JSONValue;\n};\ntype JSONArray = JSONValue[];\n\n/**\n * Tool result content part of a prompt. It contains the result of the tool call with the matching ID.\n */\nexport interface ToolResultPart {\n type: \"tool-result\";\n /**\n * ID of the tool call that this result is associated with.\n */\n toolCallId: string;\n /**\n * Name of the tool that generated this result.\n */\n toolName: string;\n /**\n * Result of the tool call. This is a JSON-serializable object.\n */\n output:\n | {\n type: \"text\";\n value: string;\n }\n | {\n type: \"json\";\n value: JSONValue;\n }\n | {\n type: \"error-text\";\n value: string;\n }\n | {\n type: \"error-json\";\n value: JSONValue;\n }\n | {\n type: \"content\";\n value: Array<\n | {\n type: \"text\";\n /**\nText content.\n*/\n text: string;\n }\n | {\n type: \"media\";\n /**\nBase-64 encoded media data.\n*/\n data: string;\n /**\nIANA media type.\n@see https://www.iana.org/assignments/media-types/media-types.xhtml\n*/\n mediaType: string;\n }\n >;\n };\n}\n\n// ============================================================================\n// Tool Types\n// ============================================================================\n\ntype ToolParameters = TSchema;\n\ntype inferParameters<PARAMETERS extends ToolParameters> = Static<PARAMETERS>;\n\n/**\n * Options passed to tool execution functions.\n */\nexport interface ToolExecutionOptions {\n /**\n * The ID of the tool call. You can use it e.g. when sending tool-call related information with stream data.\n */\n toolCallId: string;\n /**\n * Messages that were sent to the language model to initiate the response that contained the tool call.\n * The messages **do not** include the system prompt nor the assistant response that contained the tool call.\n */\n messages: AIMessage[];\n /**\n * An optional abort signal that indicates that the overall operation should be aborted.\n */\n abortSignal?: AbortSignal;\n}\n\n/**\n * A tool contains the description and the schema of the input that the tool expects.\n * This enables the language model to generate the input.\n *\n * The tool can also contain an optional execute function for the actual execution function of the tool.\n */\nexport type AITool<PARAMETERS extends ToolParameters = any, RESULT = any> = {\n /**\n * The schema of the input that the tool expects, expressed as a Typebox\n * schema. The language model uses this to generate (and the runtime to\n * validate) the tool input. Use field descriptions to make the input\n * understandable for the model.\n *\n * This is the canonical field read by the runtime. `parameters` is an\n * accepted alias for backwards compatibility.\n */\n inputSchema: TSchema;\n /**\n * @deprecated Alias for {@link inputSchema}. Prefer `inputSchema`.\n */\n parameters?: PARAMETERS;\n /**\n * An optional description of what the tool does.\n * Will be used by the language model to decide whether to use the tool.\n * Not used for provider-defined tools.\n */\n description?: string;\n /**\n * An async function that is called with the arguments from the tool call and produces a result.\n * If not provided, the tool will not be executed automatically.\n *\n * @param args - The input of the tool call\n * @param options - Execution options including abort signal and messages\n */\n execute?: (\n args: inferParameters<PARAMETERS>,\n options: ToolExecutionOptions\n ) => PromiseLike<RESULT>;\n} & (\n | {\n /**\n * Function tool.\n */\n type?: undefined | \"function\";\n }\n | {\n /**\n * Provider-defined tool.\n */\n type: \"provider-defined\";\n /**\n * The ID of the tool. Should follow the format `<provider-name>.<tool-name>`.\n */\n id: `${string}.${string}`;\n /**\n * The arguments for configuring the tool. Must match the expected arguments defined by the provider for this tool.\n */\n args: Record<string, unknown>;\n }\n);\n\n/**\n * Tool choice for the generation. It supports the following settings:\n *\n * - `auto` (default): the model can choose whether and which tools to call.\n * - `required`: the model must call a tool. It can choose which tool to call.\n * - `none`: the model must not call tools\n * - `{ type: 'tool', toolName: string (typed) }`: the model must call the specified tool\n */\ntype ToolChoice<TOOLS extends Record<string, unknown>> =\n | \"auto\"\n | \"none\"\n | \"required\"\n | {\n type: \"tool\";\n toolName: Extract<keyof TOOLS, string>;\n };\n\nexport type AIToolSet = Record<\n string,\n (\n | AITool<never, never>\n | AITool<any, any>\n | AITool<any, never>\n | AITool<never, any>\n ) &\n Pick<AITool<any, any>, \"execute\">\n>;\n\n// ============================================================================\n// Internal Helper Types\n// ============================================================================\n\ntype ToolCallUnion<_TOOLS extends AIToolSet> = {\n type: \"tool-call\";\n toolCallId: string;\n toolName: string;\n args?: unknown;\n};\n\ntype ToolCallArray<TOOLS extends AIToolSet> = Array<ToolCallUnion<TOOLS>>;\n\ntype ToolResultUnion<_TOOLS extends AIToolSet> = {\n type: \"tool-result\";\n toolCallId: string;\n toolName: string;\n args?: unknown;\n result?: unknown;\n};\n\ntype ToolResultArray<TOOLS extends AIToolSet> = Array<ToolResultUnion<TOOLS>>;\n";
8
8
  export default _default;
9
9
  //# sourceMappingURL=ai.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../../src/llm-docs/tools/ai.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;wBAEY,qnwBAAqnwB;AAApowB,wBAAqowB"}
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../../src/llm-docs/tools/ai.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;wBAEY,yhzBAA+gzB;AAA9hzB,wBAA+hzB"}