@agent-native/core 0.214.0 → 0.217.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 (196) hide show
  1. package/dist/action.js +54 -1
  2. package/dist/agent/actions/disconnect-chatgpt-subscription.js +5 -0
  3. package/dist/agent/actions/get-agentkit-capabilities.js +3 -3
  4. package/dist/agent/actions/manage-builder-connection.js +5 -0
  5. package/dist/agent/actions/manage-provider-key-policy.js +5 -0
  6. package/dist/agent/actions/manage-provider-models.js +5 -0
  7. package/dist/agent/actions/manage-service-providers.js +5 -0
  8. package/dist/agent/actions/select-chatgpt-subscription-account.js +5 -0
  9. package/dist/agent/context-xray/actions/context-evict.js +5 -0
  10. package/dist/agent/context-xray/actions/context-pin.js +5 -0
  11. package/dist/agent/context-xray/actions/context-report.js +5 -0
  12. package/dist/agent/context-xray/actions/context-restore.js +5 -0
  13. package/dist/agent/execution-fence.d.ts +1 -0
  14. package/dist/agent/execution-fence.js +5 -0
  15. package/dist/agent/production-agent.d.ts +35 -2
  16. package/dist/agent/production-agent.js +629 -32
  17. package/dist/agent/run-manager.d.ts +2 -0
  18. package/dist/agent/run-manager.js +397 -115
  19. package/dist/agent/run-slot-lock.d.ts +2 -0
  20. package/dist/agent/run-slot-lock.js +6 -0
  21. package/dist/agent/run-store.d.ts +5 -0
  22. package/dist/agent/run-store.js +423 -156
  23. package/dist/agent/thread-data-builder.js +27 -5
  24. package/dist/agent/types.d.ts +6 -12
  25. package/dist/agentkit/capabilities.d.ts +1 -1
  26. package/dist/app-config/analytics.js +1 -1
  27. package/dist/application-state/store.d.ts +5 -0
  28. package/dist/application-state/store.js +26 -0
  29. package/dist/automation/index.d.ts +1 -1
  30. package/dist/chat-threads/schema-migrations.js +17 -0
  31. package/dist/chat-threads/store.d.ts +21 -1
  32. package/dist/chat-threads/store.js +223 -41
  33. package/dist/cli/skills-content/turn-into-app-skill.d.ts +1 -1
  34. package/dist/cli/skills-content/turn-into-app-skill.js +20 -18
  35. package/dist/cli/templates-meta.js +14 -0
  36. package/dist/client/analytics-session.d.ts +7 -0
  37. package/dist/client/analytics-session.js +27 -1
  38. package/dist/client/analytics.js +276 -31
  39. package/dist/client/chat/agentkit-agent-native.js +79 -3
  40. package/dist/client/chat/agentkit-protocol.js +80 -42
  41. package/dist/client/chat/runtime.d.ts +5 -1
  42. package/dist/client/chat/runtime.js +46 -3
  43. package/dist/client/consent.d.ts +48 -0
  44. package/dist/client/consent.js +413 -0
  45. package/dist/client/onboarding/index.d.ts +1 -0
  46. package/dist/client/onboarding/index.js +1 -0
  47. package/dist/client/onboarding/use-onboarding-checklist.d.ts +23 -0
  48. package/dist/client/onboarding/use-onboarding-checklist.js +115 -0
  49. package/dist/client/review/use-review.d.ts +2 -0
  50. package/dist/client/review/use-review.js +28 -1
  51. package/dist/client/session-replay.d.ts +1 -1
  52. package/dist/client/session-replay.js +142 -3
  53. package/dist/client/sharing/useResourceAccessGate.d.ts +3 -2
  54. package/dist/client/sharing/useResourceAccessGate.js +9 -1
  55. package/dist/client/use-chat-thread-list.d.ts +2 -0
  56. package/dist/client/use-chat-thread-list.js +12 -2
  57. package/dist/client/use-chat-threads.d.ts +1 -0
  58. package/dist/client/use-chat-threads.js +2 -0
  59. package/dist/collab/awareness.d.ts +2 -2
  60. package/dist/connections/catalog.d.ts +5 -5
  61. package/dist/connections/catalog.js +22 -3
  62. package/dist/data-widgets/index.d.ts +36 -2
  63. package/dist/data-widgets/index.js +94 -6
  64. package/dist/db/migrations.js +4 -1
  65. package/dist/db/schema-snapshot.generated.js +8 -1
  66. package/dist/feature-flags/actions/set-feature-flag.js +5 -0
  67. package/dist/feature-flags/index.d.ts +1 -1
  68. package/dist/feature-flags/index.js +1 -1
  69. package/dist/feature-flags/store.d.ts +12 -0
  70. package/dist/feature-flags/store.js +79 -7
  71. package/dist/file-upload/actions/manage-file-storage.js +5 -0
  72. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  73. package/dist/file-upload/actions/upload-image.js +5 -0
  74. package/dist/history/actions/create-resource-version.js +5 -0
  75. package/dist/history/actions/restore-resource-version.js +5 -0
  76. package/dist/ingestion/index.d.ts +1 -1
  77. package/dist/ingestion/index.js +1 -1
  78. package/dist/ingestion/pptx.d.ts +11 -0
  79. package/dist/ingestion/pptx.js +81 -1
  80. package/dist/integrations/actions/manage-messaging-channel.js +5 -0
  81. package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
  82. package/dist/jobs/scheduler.js +17 -1
  83. package/dist/labs/actions/set-lab.js +5 -0
  84. package/dist/localization/actions/set-localization-preference.js +5 -0
  85. package/dist/localization/consent-banner-messages.d.ts +16 -0
  86. package/dist/localization/consent-banner-messages.js +149 -0
  87. package/dist/localization/core-messages.js +4 -0
  88. package/dist/localization/default-messages.d.ts +1 -0
  89. package/dist/localization/default-messages.js +2 -0
  90. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  91. package/dist/notifications/routes.d.ts +2 -2
  92. package/dist/observability/actions/save-observability-instruction-update.js +5 -0
  93. package/dist/observability/actions/save-observability-review-summary.js +5 -0
  94. package/dist/observability/routes.d.ts +6 -6
  95. package/dist/onboarding/index.d.ts +2 -1
  96. package/dist/onboarding/index.js +1 -0
  97. package/dist/onboarding/plugin.js +55 -46
  98. package/dist/onboarding/status.d.ts +15 -0
  99. package/dist/onboarding/status.js +59 -0
  100. package/dist/onboarding/types.d.ts +12 -0
  101. package/dist/onboarding/types.js +2 -1
  102. package/dist/org/workspace-app-access.js +19 -9
  103. package/dist/progress/routes.d.ts +1 -1
  104. package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
  105. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  106. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  107. package/dist/provider-api/index.js +9 -2
  108. package/dist/resources/handlers.d.ts +1 -1
  109. package/dist/review/actions/consume-review-feedback.js +5 -0
  110. package/dist/review/actions/create-review-comment.js +5 -0
  111. package/dist/review/actions/delete-review-comment.js +5 -0
  112. package/dist/review/actions/react-to-review-comment.js +5 -0
  113. package/dist/review/actions/reply-review-comment.js +5 -0
  114. package/dist/review/actions/resolve-review-thread.js +5 -0
  115. package/dist/review/actions/send-review-thread-to-agent.js +5 -0
  116. package/dist/review/actions/set-review-status.js +5 -0
  117. package/dist/review/actions/set-review-thread-muted.js +5 -0
  118. package/dist/review/actions/set-review-thread-unread.js +5 -0
  119. package/dist/review/actions/set-review-threads-unread.js +5 -0
  120. package/dist/review/actions/update-review-comment-anchor.js +5 -0
  121. package/dist/review/actions/update-review-comment.js +5 -0
  122. package/dist/review/suggestions/actions.js +60 -21
  123. package/dist/review/suggestions/store.d.ts +2 -0
  124. package/dist/review/suggestions/store.js +28 -0
  125. package/dist/secrets/actions/delete-api-key.js +5 -0
  126. package/dist/secrets/routes.d.ts +6 -6
  127. package/dist/server/agent-capabilities.js +13 -6
  128. package/dist/server/agent-chat/context-tools.js +63 -2
  129. package/dist/server/agent-chat-plugin.d.ts +2 -0
  130. package/dist/server/agent-chat-plugin.js +242 -54
  131. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  132. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  133. package/dist/server/analytics.d.ts +0 -1
  134. package/dist/server/analytics.js +81 -20
  135. package/dist/server/application-state-maintenance.d.ts +2 -0
  136. package/dist/server/application-state-maintenance.js +2 -0
  137. package/dist/server/attribution.d.ts +14 -0
  138. package/dist/server/attribution.js +62 -2
  139. package/dist/server/auth.js +7 -0
  140. package/dist/server/builder-api-auth.d.ts +7 -0
  141. package/dist/server/builder-api-auth.js +24 -0
  142. package/dist/server/builder-oauth.d.ts +5 -1
  143. package/dist/server/builder-oauth.js +5 -0
  144. package/dist/server/consent-route.d.ts +41 -0
  145. package/dist/server/consent-route.js +102 -0
  146. package/dist/server/core-routes-plugin.d.ts +1 -1
  147. package/dist/server/first-touch-route.d.ts +39 -0
  148. package/dist/server/first-touch-route.js +115 -0
  149. package/dist/server/index.d.ts +2 -1
  150. package/dist/server/index.js +2 -1
  151. package/dist/server/queued-submission-inbox-drain.d.ts +9 -0
  152. package/dist/server/queued-submission-inbox-drain.js +12 -0
  153. package/dist/server/request-origin.d.ts +6 -0
  154. package/dist/server/request-origin.js +12 -0
  155. package/dist/settings/org-settings.d.ts +2 -1
  156. package/dist/settings/org-settings.js +4 -1
  157. package/dist/settings/store.d.ts +8 -0
  158. package/dist/settings/store.js +14 -5
  159. package/dist/shared/consent.d.ts +33 -0
  160. package/dist/shared/consent.js +149 -0
  161. package/dist/shared/first-touch-persistence.d.ts +31 -0
  162. package/dist/shared/first-touch-persistence.js +53 -0
  163. package/dist/sharing/actions/set-resource-visibility.js +5 -0
  164. package/dist/sharing/actions/share-resource.js +5 -0
  165. package/dist/sharing/actions/unshare-resource.js +5 -0
  166. package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
  167. package/dist/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
  168. package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
  169. package/dist/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
  170. package/dist/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
  171. package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
  172. package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
  173. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
  174. package/dist/triggers/actions/manage-automation.d.ts +4 -4
  175. package/dist/usage/actions/get-usage-metrics.js +27 -4
  176. package/dist/usage/actions/manage-usage-alert.js +5 -0
  177. package/dist/vite/client.js +8 -6
  178. package/dist/workspace-connections/actions/bulk-update-workspace-user-groups.js +5 -0
  179. package/dist/workspace-connections/actions/delete-workspace-user-group.js +5 -0
  180. package/dist/workspace-connections/actions/upsert-workspace-user-group.js +5 -0
  181. package/docs/content/actions-access-control.mdx +8 -8
  182. package/docs/content/actions-defining.mdx +9 -8
  183. package/docs/content/deployment-environment-variables.mdx +1 -1
  184. package/docs/content/environment-variables.mdx +1 -1
  185. package/docs/content/template-design-developers.mdx +9 -9
  186. package/docs/content/template-design-features.mdx +1 -3
  187. package/docs/content/turn-into-app.mdx +4 -0
  188. package/package.json +6 -3
  189. package/src/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
  190. package/src/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
  191. package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
  192. package/src/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
  193. package/src/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
  194. package/src/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
  195. package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
  196. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
@@ -3,6 +3,7 @@ import { resolveLaneEndpoint } from "../shared/environment-lanes.js";
3
3
  import { loadOptionalPeer, OptionalPeerDependencyError, } from "../shared/optional-peer.js";
4
4
  import { isSyntheticTrafficValue } from "../shared/test-traffic.js";
5
5
  import { getOrCreateAnalyticsAnonymousId, getOrCreateAnalyticsSessionId, } from "./analytics-session.js";
6
+ import { whenConsentAllows } from "./consent.js";
6
7
  import { replayEndpointFromAnalyticsEndpoint } from "./session-replay-endpoint.js";
7
8
  import { SESSION_REPLAY_BLOCK_ATTRIBUTE, SESSION_REPLAY_MASK_ATTRIBUTE, } from "./session-replay-privacy.js";
8
9
  import { decideReplayQuotaResponse, parseRetryAfterSeconds, } from "./session-replay-quota.js";
@@ -1173,6 +1174,8 @@ function isDefinitiveReplayUploadClientError(status) {
1173
1174
  }
1174
1175
  const MAX_TRANSIENT_REPLAY_CLIENT_FAILURES = 3;
1175
1176
  const REPLAY_UPLOAD_TIMEOUT_MS = 15_000;
1177
+ // Uploads in flight, so a consent reject can abort them.
1178
+ const activeReplayUploads = new Set();
1176
1179
  function startReplayUploadTimeout() {
1177
1180
  const controller = typeof AbortController === "undefined" ? undefined : new AbortController();
1178
1181
  let rejectTimeout;
@@ -1186,11 +1189,17 @@ function startReplayUploadTimeout() {
1186
1189
  controller?.abort();
1187
1190
  rejectTimeout(timeoutError);
1188
1191
  }, REPLAY_UPLOAD_TIMEOUT_MS);
1192
+ if (controller)
1193
+ activeReplayUploads.add(controller);
1189
1194
  return {
1190
1195
  signal: controller?.signal,
1191
1196
  promise,
1192
1197
  didTimeout: () => timedOut,
1193
- done: () => clearTimeout(timer),
1198
+ done: () => {
1199
+ clearTimeout(timer);
1200
+ if (controller)
1201
+ activeReplayUploads.delete(controller);
1202
+ },
1194
1203
  };
1195
1204
  }
1196
1205
  function isTransientReplayUploadClientError(status) {
@@ -1543,6 +1552,13 @@ export async function flushSessionReplay(reason = "manual") {
1543
1552
  const state = getState();
1544
1553
  if (!state.options)
1545
1554
  return;
1555
+ if (replayConsentWithdrawn) {
1556
+ // An upload in flight at the reject can put its batch back; drop it.
1557
+ discardWithdrawnReplay(state);
1558
+ for (const resolve of state.pendingFlushWaiters.splice(0))
1559
+ resolve();
1560
+ return;
1561
+ }
1546
1562
  if (replayUploadsParked(state, Date.now()))
1547
1563
  return;
1548
1564
  if (state.pendingReplayUpload) {
@@ -1586,6 +1602,9 @@ export async function flushSessionReplay(reason = "manual") {
1586
1602
  return;
1587
1603
  }
1588
1604
  state.flushing = true;
1605
+ // A reject while this upload is in flight withdraws its events for good,
1606
+ // even if the visitor accepts again before it settles.
1607
+ const consentGeneration = replayConsentGeneration;
1589
1608
  let uploaded = false;
1590
1609
  let reservedSequence = false;
1591
1610
  let splitRejectedBatch = false;
@@ -1609,6 +1628,9 @@ export async function flushSessionReplay(reason = "manual") {
1609
1628
  // between; it is queued as the pending reason.
1610
1629
  const outcome = await sendReplayUpload(state.options, payload.body, {
1611
1630
  beforeUpload: (keepalive) => {
1631
+ // Compression can take long enough for a reject to land first.
1632
+ if (consentGeneration !== replayConsentGeneration)
1633
+ return "defer";
1612
1634
  const pendingReason = state.pendingFlushReason;
1613
1635
  if (!keepalive &&
1614
1636
  (isPageLeaveReplayFlushReason(reason) ||
@@ -1622,7 +1644,9 @@ export async function flushSessionReplay(reason = "manual") {
1622
1644
  },
1623
1645
  });
1624
1646
  if (outcome === "deferred") {
1625
- restoreReplayEvents(state, events);
1647
+ if (consentGeneration === replayConsentGeneration) {
1648
+ restoreReplayEvents(state, events);
1649
+ }
1626
1650
  }
1627
1651
  else {
1628
1652
  state.automaticConflictRestartAttempted = false;
@@ -1686,7 +1710,10 @@ export async function flushSessionReplay(reason = "manual") {
1686
1710
  quotaDecision?.kind === "stop") &&
1687
1711
  !splitBatch &&
1688
1712
  !isUnsplittableOversizedBatch;
1689
- if (splitBatch) {
1713
+ if (consentGeneration !== replayConsentGeneration) {
1714
+ // Withdrawn while in flight; nothing goes back on the queue.
1715
+ }
1716
+ else if (splitBatch) {
1690
1717
  state.retryBatches.unshift(...splitBatch);
1691
1718
  splitRejectedBatch = true;
1692
1719
  }
@@ -1811,10 +1838,18 @@ export async function flushSessionReplay(reason = "manual") {
1811
1838
  if (shouldRestartAfterConflict) {
1812
1839
  state.automaticConflictRestartAttempted = true;
1813
1840
  }
1841
+ // The stop forgets the caller's start; a recovered recording keeps it,
1842
+ // so a reject and a later accept can bring it back.
1843
+ const consentStartOptions = replayAllowedOptions;
1814
1844
  await stopSessionReplay("upload-rejected");
1815
1845
  let restartResult = null;
1816
1846
  if (shouldRestartAfterConflict && rejectedOptions) {
1817
1847
  restartResult = await restartSessionReplayWithFreshIdentity(state, rejectedOptions, payload.sessionId);
1848
+ if (restartResult.started)
1849
+ replayAllowedOptions = consentStartOptions;
1850
+ // A reject during the recovery leaves the start for the next accept.
1851
+ if (!replayConsentGranted)
1852
+ replayAwaitingConsent ??= consentStartOptions;
1818
1853
  }
1819
1854
  const details = {
1820
1855
  status: definitiveClientErrorStatus,
@@ -1861,6 +1896,16 @@ async function restartSessionReplayWithFreshIdentityInternal(state, options, ses
1861
1896
  if (options.shouldStart && !options.shouldStart()) {
1862
1897
  return { started: false, reason: "disabled", sessionId, sampled: true };
1863
1898
  }
1899
+ // Recovery restarts without going through startSessionReplay, so a reject
1900
+ // that landed while the old recording stopped must still hold here.
1901
+ if (!replayConsentGranted) {
1902
+ return {
1903
+ started: false,
1904
+ reason: "consent-required",
1905
+ sessionId,
1906
+ sampled: true,
1907
+ };
1908
+ }
1864
1909
  const initialProperties = replayExtraProperties(options);
1865
1910
  if (options.requireSignedInUser && !replayUserEmail(initialProperties)) {
1866
1911
  return {
@@ -2687,6 +2732,81 @@ function installCaptureInterceptors(state) {
2687
2732
  }
2688
2733
  };
2689
2734
  }
2735
+ let replayConsentWatched = false;
2736
+ let replayConsentGranted = false;
2737
+ let replayConsentWithdrawn = false;
2738
+ let replayConsentGeneration = 0;
2739
+ let replayAllowedOptions = null;
2740
+ function discardWithdrawnReplay(state) {
2741
+ for (const upload of activeReplayUploads)
2742
+ upload.abort();
2743
+ activeReplayUploads.clear();
2744
+ state.queue = [];
2745
+ state.queuedBytes = 0;
2746
+ state.retryBatches = [];
2747
+ state.pendingFlushReason = null;
2748
+ for (const resolve of state.pendingFlushWaiters.splice(0))
2749
+ resolve();
2750
+ }
2751
+ let replayAwaitingConsent = null;
2752
+ let replayCallerStops = 0;
2753
+ /**
2754
+ * Replay waits for analytics consent where the banner applies, without the
2755
+ * time zone's early guess: a recording that already uploaded can't be undone.
2756
+ * A start asked for before the answer runs once consent arrives.
2757
+ */
2758
+ function replayConsentAllows(options) {
2759
+ if (!replayConsentWatched) {
2760
+ replayConsentWatched = true;
2761
+ whenConsentAllows("performance", () => {
2762
+ replayConsentGranted = true;
2763
+ // What an upload in flight at the reject put back stays withdrawn.
2764
+ if (replayConsentWithdrawn)
2765
+ discardWithdrawnReplay(getState());
2766
+ replayConsentWithdrawn = false;
2767
+ const waiting = replayAwaitingConsent;
2768
+ replayAwaitingConsent = null;
2769
+ if (!waiting)
2770
+ return;
2771
+ // A reject during the last start cancels it, and an accept that
2772
+ // quickly gets that canceled start back; ask once more after it.
2773
+ const stops = replayCallerStops;
2774
+ void startSessionReplay(waiting).then((result) => {
2775
+ if (!result.started &&
2776
+ replayConsentGranted &&
2777
+ !getState().active &&
2778
+ replayCallerStops === stops) {
2779
+ void startSessionReplay(waiting);
2780
+ }
2781
+ });
2782
+ }, {
2783
+ // The region's first answer revokes before any choice, so a start
2784
+ // asked for earlier keeps waiting for an accept.
2785
+ revoke: () => {
2786
+ const wasGranted = replayConsentGranted;
2787
+ replayConsentGranted = false;
2788
+ if (!wasGranted) {
2789
+ // A replay id an earlier page stored never carries past a reject.
2790
+ const storedReplayId = readStoredReplaySession()?.replayId;
2791
+ if (storedReplayId)
2792
+ removeStoredReplaySession(storedReplayId);
2793
+ return;
2794
+ }
2795
+ replayConsentWithdrawn = true;
2796
+ replayConsentGeneration += 1;
2797
+ // A fresh accept on this page records again, under a new identity.
2798
+ replayAwaitingConsent = replayAllowedOptions ?? replayAwaitingConsent;
2799
+ void stopSessionReplay("consent-revoked");
2800
+ },
2801
+ });
2802
+ }
2803
+ if (replayConsentGranted) {
2804
+ replayAllowedOptions = options;
2805
+ return true;
2806
+ }
2807
+ replayAwaitingConsent = options;
2808
+ return false;
2809
+ }
2690
2810
  export async function startSessionReplay(options = {}) {
2691
2811
  if (isSyntheticBrowserTraffic()) {
2692
2812
  return { started: false, reason: "disabled" };
@@ -2702,6 +2822,9 @@ export async function startSessionReplay(options = {}) {
2702
2822
  const normalized = normalizeOptions(options);
2703
2823
  if (!normalized)
2704
2824
  return { started: false, reason: "missing-public-key" };
2825
+ if (!replayConsentAllows(options)) {
2826
+ return { started: false, reason: "consent-required" };
2827
+ }
2705
2828
  const sessionId = getOrCreateAnalyticsSessionId();
2706
2829
  if (!sessionId)
2707
2830
  return { started: false, reason: "missing-session-id" };
@@ -2965,6 +3088,19 @@ export async function stopSessionReplay(reason = "manual") {
2965
3088
  if (reason !== "pagehide-persisted") {
2966
3089
  state.bfcacheRestored = false;
2967
3090
  }
3091
+ if (reason === "consent-revoked") {
3092
+ // Also when recording already stopped: a later accept starts afresh.
3093
+ const storedReplayId = state.replayId ?? readStoredReplaySession()?.replayId;
3094
+ discardWithdrawnReplay(state);
3095
+ if (storedReplayId)
3096
+ removeStoredReplaySession(storedReplayId);
3097
+ }
3098
+ else if (reason !== "upload-timeout") {
3099
+ // Any other stop is final: a later accept doesn't bring it back.
3100
+ replayAwaitingConsent = null;
3101
+ replayAllowedOptions = null;
3102
+ replayCallerStops += 1;
3103
+ }
2968
3104
  if (!state.active) {
2969
3105
  if (authClearedReplayId)
2970
3106
  removeStoredReplaySession(authClearedReplayId);
@@ -3024,6 +3160,9 @@ export async function stopSessionReplay(reason = "manual") {
3024
3160
  // best-effort cleanup
3025
3161
  }
3026
3162
  state.broadcastChannel = null;
3163
+ // A reject withdraws what is still buffered, so it is never uploaded.
3164
+ if (reason === "consent-revoked")
3165
+ return;
3027
3166
  const sequenceBeforeFinalFlush = state.sequence;
3028
3167
  try {
3029
3168
  await flushSessionReplay(reason);
@@ -30,8 +30,9 @@ export interface ResourceAccessGateOptions {
30
30
  * Called once when the status says the viewer can open the resource: either
31
31
  * the read that failed should be tried again, or the owner shared it while
32
32
  * this screen was open. The status is checked again whenever the window
33
- * regains focus, including switching back from another browser window, and
34
- * every half minute while the viewer's request is open.
33
+ * regains focus, including switching back from another browser window,
34
+ * every half minute while the viewer's request is open, and every 12 seconds
35
+ * while the resource is in Trash.
35
36
  */
36
37
  onAccessGranted?: () => void;
37
38
  }
@@ -4,6 +4,10 @@ import { useActionMutation, useActionQuery } from "../use-action.js";
4
4
  // While a request is open, approving it should open the resource without a
5
5
  // manual reload, even when the window never loses focus.
6
6
  const PENDING_REQUEST_POLL_MS = 30_000;
7
+ // This screen replaces the resource's own view, and with it that view's sync
8
+ // poll, so a restore made elsewhere would otherwise wait for focus or the
9
+ // app-wide idle poll, which backs off to minutes. 12 s is that view's poll.
10
+ const TRASHED_POLL_MS = 12_000;
7
11
  function requestFailure(error) {
8
12
  const failure = error;
9
13
  return {
@@ -24,7 +28,11 @@ export function useResourceAccessGate({ resourceType, resourceId, enabled = true
24
28
  enabled,
25
29
  refetchOnWindowFocus: "always",
26
30
  staleTime: 0,
27
- refetchInterval: (current) => current.state.data?.request ? PENDING_REQUEST_POLL_MS : false,
31
+ refetchInterval: (current) => current.state.data?.state === "trashed"
32
+ ? TRASHED_POLL_MS
33
+ : current.state.data?.request
34
+ ? PENDING_REQUEST_POLL_MS
35
+ : false,
28
36
  });
29
37
  const request = useActionMutation("request-resource-access");
30
38
  const state = query.data?.state;
@@ -6,6 +6,8 @@ export interface UseChatThreadListOptions {
6
6
  pageSize?: number;
7
7
  scope?: ChatThreadScope | null;
8
8
  includeExternal?: boolean;
9
+ /** Include archived threads. Defaults to false. */
10
+ includeArchived?: boolean;
9
11
  /** Search text. Empty lists the whole set. */
10
12
  query?: string;
11
13
  /** When false nothing is fetched and the list is empty. Defaults to true. */
@@ -48,7 +48,7 @@ function createListState(identity, enabled) {
48
48
  * rather than collapsing to the first page.
49
49
  */
50
50
  export function useChatThreadList(options) {
51
- const { ownership, includeExternal = false, enabled = true, refreshOnThreadUpdates = true, } = options;
51
+ const { ownership, includeExternal = false, includeArchived = false, enabled = true, refreshOnThreadUpdates = true, } = options;
52
52
  const apiUrl = options.apiUrl ?? agentNativePath("/_agent-native/agent-chat");
53
53
  const pageSize = resolvePageSize(options.pageSize);
54
54
  const query = options.query?.trim() ?? "";
@@ -62,6 +62,7 @@ export function useChatThreadList(options) {
62
62
  scopeId,
63
63
  pageSize,
64
64
  includeExternal,
65
+ includeArchived,
65
66
  enabled,
66
67
  ]);
67
68
  const [stored, setState] = useState(() => createListState(identity, enabled));
@@ -89,6 +90,7 @@ export function useChatThreadList(options) {
89
90
  query,
90
91
  ownership,
91
92
  includeExternal,
93
+ includeArchived,
92
94
  scope: scopeType && scopeId ? { type: scopeType, id: scopeId } : null,
93
95
  }).then((result) => {
94
96
  if (result.hasMore === undefined) {
@@ -100,7 +102,15 @@ export function useChatThreadList(options) {
100
102
  throw new ChatThreadListError("Chat history response reported more threads but returned none.");
101
103
  }
102
104
  return { threads: result.threads, hasMore: result.hasMore };
103
- }), [apiUrl, includeExternal, ownership, query, scopeId, scopeType]);
105
+ }), [
106
+ apiUrl,
107
+ includeArchived,
108
+ includeExternal,
109
+ ownership,
110
+ query,
111
+ scopeId,
112
+ scopeType,
113
+ ]);
104
114
  // Reload the first `window` server rows, one capped page at a time, and swap
105
115
  // them in only once every page has arrived. A failure part-way leaves the
106
116
  // rows and offset already on screen untouched.
@@ -98,6 +98,7 @@ export interface ChatThreadListPageRequest {
98
98
  query?: string;
99
99
  ownership?: ChatThreadOwnership;
100
100
  includeExternal?: boolean;
101
+ includeArchived?: boolean;
101
102
  scope?: ChatThreadScope | null;
102
103
  }
103
104
  /** A listed thread as the server returns it: ownership metadata always present. */
@@ -120,6 +120,8 @@ async function requestChatThreadListPage(request) {
120
120
  }
121
121
  if (request.includeExternal)
122
122
  params.set("includeExternal", "1");
123
+ if (request.includeArchived)
124
+ params.set("includeArchived", "1");
123
125
  appendChatThreadScopeParams(params, request.scope);
124
126
  const search = params.toString();
125
127
  const res = await fetch(`${apiUrl}/threads${search ? `?${search}` : ""}`);
@@ -38,19 +38,19 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
38
38
  error: string;
39
39
  states?: undefined;
40
40
  } | {
41
- error?: undefined;
42
41
  states: {
43
42
  clientId: number;
44
43
  state: string;
45
44
  }[];
45
+ error?: undefined;
46
46
  }>>;
47
47
  export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
48
48
  error: string;
49
49
  users?: undefined;
50
50
  } | {
51
- error?: undefined;
52
51
  users: {
53
52
  clientId: number;
54
53
  lastSeen: number;
55
54
  }[];
55
+ error?: undefined;
56
56
  }>>;
@@ -1,5 +1,5 @@
1
1
  export type WorkspaceConnectionCapability = "search" | "import" | "messages" | "meetings" | "crm" | "code" | "docs";
2
- export type WorkspaceConnectionTemplateUse = "analytics" | "brain" | "calendar" | "clips" | "content" | "crm" | "design" | "dispatch" | "factory" | "forms" | "mail" | "slides";
2
+ export type WorkspaceConnectionTemplateUse = "analytics" | "brain" | "calendar" | "clips" | "content" | "crm" | "design" | "dispatch" | "factory" | "forms" | "mail" | "slides" | "slides-2";
3
3
  export type WorkspaceConnectionProviderId = "slack" | "github" | "figma" | "notion" | "gmail" | "google_calendar" | "google_drive" | "bigquery" | "google_docs" | "google_sheets" | "google_slides" | "hubspot" | "salesforce" | "jira" | "sentry" | "granola" | "clips" | "dbt" | "sigma" | "anthropic-managed-agents" | "generic";
4
4
  export interface WorkspaceConnectionCredentialKey {
5
5
  key: string;
@@ -84,7 +84,7 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
84
84
  readonly scopes: readonly ["current_user:read", "file_content:read", "file_metadata:read", "projects:read"];
85
85
  };
86
86
  readonly capabilities: readonly ["search", "import", "docs"];
87
- readonly recommendedTemplateUses: readonly ["brain", "design", "slides", "content"];
87
+ readonly recommendedTemplateUses: readonly ["brain", "design", "slides", "slides-2", "content"];
88
88
  }, {
89
89
  readonly id: "notion";
90
90
  readonly label: "Notion";
@@ -184,7 +184,7 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
184
184
  readonly required: true;
185
185
  }];
186
186
  readonly capabilities: readonly ["search", "import", "docs"];
187
- readonly recommendedTemplateUses: readonly ["brain", "content", "slides", "dispatch", "analytics"];
187
+ readonly recommendedTemplateUses: readonly ["brain", "content", "slides", "slides-2", "dispatch", "analytics"];
188
188
  readonly oauth: {
189
189
  authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth";
190
190
  tokenUrl: "https://oauth2.googleapis.com/token";
@@ -207,7 +207,7 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
207
207
  readonly required: true;
208
208
  }];
209
209
  readonly capabilities: readonly ["search", "import", "docs"];
210
- readonly recommendedTemplateUses: readonly ["brain", "content", "slides", "dispatch"];
210
+ readonly recommendedTemplateUses: readonly ["brain", "content", "slides", "slides-2", "dispatch"];
211
211
  readonly oauth: {
212
212
  authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth";
213
213
  tokenUrl: "https://oauth2.googleapis.com/token";
@@ -253,7 +253,7 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
253
253
  readonly required: true;
254
254
  }];
255
255
  readonly capabilities: readonly ["search", "import", "docs"];
256
- readonly recommendedTemplateUses: readonly ["brain", "content", "slides", "dispatch"];
256
+ readonly recommendedTemplateUses: readonly ["brain", "content", "slides", "slides-2", "dispatch"];
257
257
  readonly oauth: {
258
258
  authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth";
259
259
  tokenUrl: "https://oauth2.googleapis.com/token";
@@ -92,7 +92,13 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
92
92
  ],
93
93
  },
94
94
  capabilities: ["search", "import", "docs"],
95
- recommendedTemplateUses: ["brain", "design", "slides", "content"],
95
+ recommendedTemplateUses: [
96
+ "brain",
97
+ "design",
98
+ "slides",
99
+ "slides-2",
100
+ "content",
101
+ ],
96
102
  }),
97
103
  defineWorkspaceConnectionProvider({
98
104
  id: "notion",
@@ -161,6 +167,7 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
161
167
  "brain",
162
168
  "content",
163
169
  "slides",
170
+ "slides-2",
164
171
  "dispatch",
165
172
  "analytics",
166
173
  ],
@@ -176,7 +183,13 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
176
183
  description: "Google Docs files for source material, document search, and agent-assisted writing workflows.",
177
184
  credentialKeys: GOOGLE_CREDENTIAL_KEYS,
178
185
  capabilities: ["search", "import", "docs"],
179
- recommendedTemplateUses: ["brain", "content", "slides", "dispatch"],
186
+ recommendedTemplateUses: [
187
+ "brain",
188
+ "content",
189
+ "slides",
190
+ "slides-2",
191
+ "dispatch",
192
+ ],
180
193
  oauth: googleOAuth([
181
194
  ...GOOGLE_IDENTITY_SCOPES,
182
195
  "https://www.googleapis.com/auth/documents.readonly",
@@ -197,7 +210,13 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
197
210
  description: "Google Slides presentations for reference imports, visual context, and presentation workflows.",
198
211
  credentialKeys: GOOGLE_CREDENTIAL_KEYS,
199
212
  capabilities: ["search", "import", "docs"],
200
- recommendedTemplateUses: ["brain", "content", "slides", "dispatch"],
213
+ recommendedTemplateUses: [
214
+ "brain",
215
+ "content",
216
+ "slides",
217
+ "slides-2",
218
+ "dispatch",
219
+ ],
201
220
  oauth: googleOAuth([
202
221
  ...GOOGLE_IDENTITY_SCOPES,
203
222
  "https://www.googleapis.com/auth/presentations.readonly",