@agent-native/core 0.98.5 → 0.98.7

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 (135) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +18 -0
  3. package/corpus/core/docs/content/external-agents.mdx +66 -7
  4. package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +40 -7
  5. package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +41 -7
  6. package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +41 -7
  7. package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +41 -7
  8. package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +40 -7
  9. package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +40 -7
  10. package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +40 -7
  11. package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +41 -7
  12. package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +39 -7
  13. package/corpus/core/docs/content/locales/zh-TW/external-agents.mdx +39 -7
  14. package/corpus/core/package.json +1 -1
  15. package/corpus/core/src/a2a/handlers.ts +101 -26
  16. package/corpus/core/src/a2a/task-store.ts +128 -3
  17. package/corpus/core/src/client/session-replay.ts +67 -5
  18. package/corpus/core/src/integrations/adapters/slack.ts +207 -17
  19. package/corpus/core/src/integrations/identity-links-store.ts +210 -0
  20. package/corpus/core/src/integrations/identity.ts +196 -0
  21. package/corpus/core/src/integrations/index.ts +6 -0
  22. package/corpus/core/src/integrations/plugin.ts +130 -1
  23. package/corpus/core/src/integrations/types.ts +37 -0
  24. package/corpus/core/src/integrations/webhook-handler.ts +1 -0
  25. package/corpus/core/src/mcp/build-server.ts +127 -22
  26. package/corpus/core/src/mcp/builtin-tools.ts +5 -2
  27. package/corpus/core/src/mcp/external-agent-policy.ts +18 -0
  28. package/corpus/core/src/mcp/index.ts +1 -0
  29. package/corpus/core/src/server/agent-chat/plugin-options.ts +12 -1
  30. package/corpus/core/src/server/agent-chat/script-entries.ts +20 -3
  31. package/corpus/core/src/server/agent-chat-plugin.ts +3 -0
  32. package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +34 -5
  33. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +4 -1
  34. package/corpus/templates/analytics/AGENTS.md +20 -5
  35. package/corpus/templates/analytics/actions/create-session-replay-agent-link.ts +0 -1
  36. package/corpus/templates/analytics/actions/get-session-replay-events.ts +0 -1
  37. package/corpus/templates/analytics/actions/get-session-replay-timeline.ts +40 -0
  38. package/corpus/templates/analytics/actions/list-error-issues.ts +12 -0
  39. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +4 -1
  40. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +48 -17
  41. package/corpus/templates/analytics/changelog/2026-07-12-analytics-uses-the-full-in-app-agent-for-multi-step-incident.md +6 -0
  42. package/corpus/templates/analytics/changelog/2026-07-12-connected-external-agents-can-now-look-up-sessions-error-iss.md +6 -0
  43. package/corpus/templates/analytics/changelog/2026-07-12-session-identities-stay-visible-when-demo-mode-is-off.md +6 -0
  44. package/corpus/templates/analytics/server/handlers/session-replay.ts +15 -9
  45. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +2 -2
  46. package/corpus/templates/analytics/server/lib/error-capture.ts +47 -5
  47. package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +72 -22
  48. package/corpus/templates/analytics/server/lib/session-replay.ts +41 -11
  49. package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -0
  50. package/corpus/templates/analytics/server/plugins/db.ts +15 -0
  51. package/corpus/templates/analytics/server/routes/api/session-replay/agent-diagnostics.json.get.ts +8 -5
  52. package/corpus/templates/analytics/server/routes/api/session-replay/agent-events.json.get.ts +8 -3
  53. package/corpus/templates/calendar/app/components/calendar/DeleteEventDialog.tsx +12 -2
  54. package/corpus/templates/forms/app/global.css +54 -8
  55. package/corpus/templates/forms/app/pages/AskPage.tsx +35 -13
  56. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +11 -17
  57. package/corpus/templates/forms/app/pages/ResponsesPage.tsx +8 -5
  58. package/corpus/templates/forms/changelog/2026-07-12-ask-forms-suggestions-now-sit-beneath-the-composer-for-a-tig.md +6 -0
  59. package/corpus/templates/forms/changelog/2026-07-12-builder-response-tables-now-fill-the-view-without-a-redundan.md +6 -0
  60. package/corpus/templates/forms/changelog/2026-07-12-response-tables-now-fill-the-available-pane-with-a-flexible-.md +6 -0
  61. package/corpus/templates/mail/AGENTS.md +3 -1
  62. package/corpus/templates/mail/server/lib/mail-integrations.ts +3 -0
  63. package/dist/a2a/handlers.d.ts.map +1 -1
  64. package/dist/a2a/handlers.js +89 -20
  65. package/dist/a2a/handlers.js.map +1 -1
  66. package/dist/a2a/task-store.d.ts +32 -1
  67. package/dist/a2a/task-store.d.ts.map +1 -1
  68. package/dist/a2a/task-store.js +111 -4
  69. package/dist/a2a/task-store.js.map +1 -1
  70. package/dist/client/session-replay.d.ts.map +1 -1
  71. package/dist/client/session-replay.js +53 -8
  72. package/dist/client/session-replay.js.map +1 -1
  73. package/dist/collab/routes.d.ts +1 -1
  74. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  75. package/dist/integrations/adapters/slack.js +176 -17
  76. package/dist/integrations/adapters/slack.js.map +1 -1
  77. package/dist/integrations/identity-links-store.d.ts +23 -0
  78. package/dist/integrations/identity-links-store.d.ts.map +1 -0
  79. package/dist/integrations/identity-links-store.js +158 -0
  80. package/dist/integrations/identity-links-store.js.map +1 -0
  81. package/dist/integrations/identity.d.ts +28 -0
  82. package/dist/integrations/identity.d.ts.map +1 -0
  83. package/dist/integrations/identity.js +142 -0
  84. package/dist/integrations/identity.js.map +1 -0
  85. package/dist/integrations/index.d.ts +2 -0
  86. package/dist/integrations/index.d.ts.map +1 -1
  87. package/dist/integrations/index.js +2 -0
  88. package/dist/integrations/index.js.map +1 -1
  89. package/dist/integrations/plugin.d.ts.map +1 -1
  90. package/dist/integrations/plugin.js +93 -1
  91. package/dist/integrations/plugin.js.map +1 -1
  92. package/dist/integrations/types.d.ts +31 -0
  93. package/dist/integrations/types.d.ts.map +1 -1
  94. package/dist/integrations/types.js.map +1 -1
  95. package/dist/integrations/webhook-handler.js +1 -0
  96. package/dist/integrations/webhook-handler.js.map +1 -1
  97. package/dist/mcp/build-server.d.ts +9 -2
  98. package/dist/mcp/build-server.d.ts.map +1 -1
  99. package/dist/mcp/build-server.js +97 -20
  100. package/dist/mcp/build-server.js.map +1 -1
  101. package/dist/mcp/builtin-tools.d.ts.map +1 -1
  102. package/dist/mcp/builtin-tools.js +5 -2
  103. package/dist/mcp/builtin-tools.js.map +1 -1
  104. package/dist/mcp/external-agent-policy.d.ts +19 -0
  105. package/dist/mcp/external-agent-policy.d.ts.map +1 -0
  106. package/dist/mcp/external-agent-policy.js +2 -0
  107. package/dist/mcp/external-agent-policy.js.map +1 -0
  108. package/dist/mcp/index.d.ts +1 -0
  109. package/dist/mcp/index.d.ts.map +1 -1
  110. package/dist/mcp/index.js.map +1 -1
  111. package/dist/notifications/routes.d.ts +1 -1
  112. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  113. package/dist/server/agent-chat/plugin-options.d.ts +11 -1
  114. package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
  115. package/dist/server/agent-chat/plugin-options.js.map +1 -1
  116. package/dist/server/agent-chat/script-entries.d.ts.map +1 -1
  117. package/dist/server/agent-chat/script-entries.js +16 -2
  118. package/dist/server/agent-chat/script-entries.js.map +1 -1
  119. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  120. package/dist/server/agent-chat-plugin.js +3 -0
  121. package/dist/server/agent-chat-plugin.js.map +1 -1
  122. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +34 -5
  123. package/docs/content/external-agents.mdx +66 -7
  124. package/docs/content/locales/ar-SA/external-agents.mdx +40 -7
  125. package/docs/content/locales/de-DE/external-agents.mdx +41 -7
  126. package/docs/content/locales/es-ES/external-agents.mdx +41 -7
  127. package/docs/content/locales/fr-FR/external-agents.mdx +41 -7
  128. package/docs/content/locales/hi-IN/external-agents.mdx +40 -7
  129. package/docs/content/locales/ja-JP/external-agents.mdx +40 -7
  130. package/docs/content/locales/ko-KR/external-agents.mdx +40 -7
  131. package/docs/content/locales/pt-BR/external-agents.mdx +41 -7
  132. package/docs/content/locales/zh-CN/external-agents.mdx +39 -7
  133. package/docs/content/locales/zh-TW/external-agents.mdx +39 -7
  134. package/package.json +1 -1
  135. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +34 -5
@@ -41,9 +41,9 @@ export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import
41
41
  * Body: { text: string, fieldName?: string, requestSource?: string }
42
42
  */
43
43
  export declare const postCollabText: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
44
+ text?: undefined;
44
45
  ok?: undefined;
45
46
  error: string;
46
- text?: undefined;
47
47
  } | {
48
48
  error?: undefined;
49
49
  ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/integrations/adapters/slack.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EAQhB,MAAM,aAAa,CAAC;AAcrB,MAAM,WAAW,mBAAmB;IAClC,8DAA8D;IAC9D,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7E,kEAAkE;IAClE,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACjE,oEAAoE;IACpE,oBAAoB,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAC1B,OAAO,GAAE,mBAAwB,GAChC,eAAe,CA2fjB"}
1
+ {"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/integrations/adapters/slack.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EAQhB,MAAM,aAAa,CAAC;AAwDrB,MAAM,WAAW,mBAAmB;IAClC,8DAA8D;IAC9D,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7E,kEAAkE;IAClE,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACjE,oEAAoE;IACpE,oBAAoB,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAC1B,OAAO,GAAE,mBAAwB,GAChC,eAAe,CAgjBjB"}
@@ -18,6 +18,36 @@ const SLACK_PERMALINK_TIMEOUT_MS = 1_000;
18
18
  const SLACK_CONTEXT_MESSAGE_LIMIT = 15;
19
19
  const SLACK_CONTEXT_TEXT_LIMIT = 2_000;
20
20
  const SLACK_CALM_PROGRESS_THRESHOLD_SECONDS = 30;
21
+ const SLACK_IDENTITY_TIMEOUT_MS = 1_000;
22
+ const SLACK_IDENTITY_CACHE_TTL_MS = 10 * 60 * 1_000;
23
+ // Failed users.info lookups only get a short negative TTL: a transient Slack
24
+ // API blip must not fail-close a sender's identity (and DMs) for 10 minutes.
25
+ const SLACK_IDENTITY_NEGATIVE_CACHE_TTL_MS = 30 * 1_000;
26
+ const SLACK_IDENTITY_CACHE_MAX_ENTRIES = 1_000;
27
+ const slackIdentityCache = new Map();
28
+ // Deduped system notices send at most once per key per TTL so senders are
29
+ // informed without being spammed per message. Callers pick the window: the
30
+ // anonymous-tier heads-up uses the default day-long TTL; decline replies pass
31
+ // a short TTL so a persistent condition still reminds the sender occasionally.
32
+ const SLACK_SYSTEM_NOTICE_DEDUPE_TTL_MS = 24 * 60 * 60 * 1_000;
33
+ const SLACK_SYSTEM_NOTICE_CACHE_MAX_ENTRIES = 1_000;
34
+ const slackSystemNoticeCache = new Map();
35
+ /** Returns true when a deduped notice should send now, claiming the slot. */
36
+ function claimSlackSystemNoticeSlot(key, ttlMs = SLACK_SYSTEM_NOTICE_DEDUPE_TTL_MS) {
37
+ const now = Date.now();
38
+ const expiresAt = slackSystemNoticeCache.get(key);
39
+ if (expiresAt && expiresAt > now)
40
+ return false;
41
+ if (expiresAt)
42
+ slackSystemNoticeCache.delete(key);
43
+ if (slackSystemNoticeCache.size >= SLACK_SYSTEM_NOTICE_CACHE_MAX_ENTRIES) {
44
+ const oldestKey = slackSystemNoticeCache.keys().next().value;
45
+ if (oldestKey)
46
+ slackSystemNoticeCache.delete(oldestKey);
47
+ }
48
+ slackSystemNoticeCache.set(key, now + ttlMs);
49
+ return true;
50
+ }
21
51
  /**
22
52
  * Create a Slack platform adapter.
23
53
  *
@@ -194,7 +224,10 @@ export function slackAdapter(options = {}) {
194
224
  triggerKind: isDm ? "dm" : isMention ? "mention" : "thread_reply",
195
225
  conversationType: isDm ? "dm" : "unknown",
196
226
  tenantId: teamId,
197
- actorTrust: { memberType: "unknown", verified: true },
227
+ // The signed Slack envelope authenticates the workspace, not the
228
+ // sender's membership tier. `users.info` hydration below is the
229
+ // authority that may promote this to a verified member.
230
+ actorTrust: { memberType: "unknown", verified: false },
198
231
  platformContext: {
199
232
  channelId: e.channel,
200
233
  channelType: e.channel_type,
@@ -283,6 +316,12 @@ export function slackAdapter(options = {}) {
283
316
  return incoming;
284
317
  return hydrateSlackContext(token, incoming);
285
318
  },
319
+ async hydrateIncomingIdentity(incoming) {
320
+ const token = await resolveBotToken(incoming);
321
+ if (!token)
322
+ return incoming;
323
+ return hydrateSlackIdentity(token, incoming);
324
+ },
286
325
  async startRunProgress(incoming) {
287
326
  const token = await resolveBotToken(incoming);
288
327
  if (!token)
@@ -375,6 +414,45 @@ export function slackAdapter(options = {}) {
375
414
  throw err;
376
415
  }
377
416
  },
417
+ async sendSystemNotice(incoming, text, opts) {
418
+ if (!text.trim())
419
+ return;
420
+ const dedupeKey = opts?.dedupeKey;
421
+ if (dedupeKey &&
422
+ !claimSlackSystemNoticeSlot(dedupeKey, opts?.dedupeTtlMs)) {
423
+ return;
424
+ }
425
+ try {
426
+ const token = await resolveBotToken(incoming);
427
+ if (!token) {
428
+ if (dedupeKey)
429
+ slackSystemNoticeCache.delete(dedupeKey);
430
+ return;
431
+ }
432
+ const channelId = incoming.platformContext.channelId;
433
+ if (typeof channelId !== "string" || !channelId) {
434
+ if (dedupeKey)
435
+ slackSystemNoticeCache.delete(dedupeKey);
436
+ return;
437
+ }
438
+ const threadTs = typeof incoming.platformContext.threadTs === "string"
439
+ ? incoming.platformContext.threadTs
440
+ : undefined;
441
+ await postFresh(token, channelId, threadTs, {
442
+ text,
443
+ unfurl_links: false,
444
+ unfurl_media: false,
445
+ mrkdwn: true,
446
+ });
447
+ }
448
+ catch (error) {
449
+ // A failed delivery did not inform the sender, so release the slot and
450
+ // allow the next message to retry instead of suppressing notices for a day.
451
+ if (dedupeKey)
452
+ slackSystemNoticeCache.delete(dedupeKey);
453
+ throw error;
454
+ }
455
+ },
378
456
  async sendMessageToTarget(message, target) {
379
457
  const targetContext = {
380
458
  platform: "slack",
@@ -873,6 +951,88 @@ async function slackJson(token, method, params, timeoutMs = 2_000) {
873
951
  return null;
874
952
  }
875
953
  }
954
+ function slackIdentityCacheKey(incoming) {
955
+ const teamId = incoming.platformContext.teamId;
956
+ const senderId = incoming.senderId;
957
+ if (typeof senderId !== "string" || !senderId.trim())
958
+ return null;
959
+ return `${typeof teamId === "string" && teamId ? teamId : "unknown"}:${senderId}`;
960
+ }
961
+ async function resolveSlackUserIdentity(token, incoming) {
962
+ const cacheKey = slackIdentityCacheKey(incoming);
963
+ if (!cacheKey)
964
+ return null;
965
+ const cached = slackIdentityCache.get(cacheKey);
966
+ if (cached && cached.expiresAt > Date.now())
967
+ return cached.identity;
968
+ if (cached)
969
+ slackIdentityCache.delete(cacheKey);
970
+ const user = await slackJson(token, "users.info", { user: incoming.senderId }, SLACK_IDENTITY_TIMEOUT_MS);
971
+ const profile = user?.user?.profile;
972
+ const identity = user?.user
973
+ ? {
974
+ email: typeof profile?.email === "string" && profile.email.trim()
975
+ ? profile.email.trim().toLowerCase()
976
+ : null,
977
+ name: typeof profile?.real_name === "string" && profile.real_name.trim()
978
+ ? profile.real_name.trim()
979
+ : typeof profile?.display_name === "string" &&
980
+ profile.display_name.trim()
981
+ ? profile.display_name.trim()
982
+ : typeof user.user.real_name === "string" &&
983
+ user.user.real_name.trim()
984
+ ? user.user.real_name.trim()
985
+ : typeof user.user.name === "string" && user.user.name.trim()
986
+ ? user.user.name.trim()
987
+ : null,
988
+ // is_stranger marks Slack Connect DM participants from another
989
+ // workspace; they must map to "external", never "member".
990
+ memberType: user.user.is_stranger || user.user.is_ultra_restricted
991
+ ? "external"
992
+ : user.user.is_restricted
993
+ ? "guest"
994
+ : user.user.is_owner
995
+ ? "owner"
996
+ : user.user.is_admin
997
+ ? "admin"
998
+ : "member",
999
+ }
1000
+ : null;
1001
+ if (slackIdentityCache.size >= SLACK_IDENTITY_CACHE_MAX_ENTRIES) {
1002
+ const oldestKey = slackIdentityCache.keys().next().value;
1003
+ if (oldestKey)
1004
+ slackIdentityCache.delete(oldestKey);
1005
+ }
1006
+ slackIdentityCache.set(cacheKey, {
1007
+ identity,
1008
+ expiresAt: Date.now() +
1009
+ (identity
1010
+ ? SLACK_IDENTITY_CACHE_TTL_MS
1011
+ : SLACK_IDENTITY_NEGATIVE_CACHE_TTL_MS),
1012
+ });
1013
+ return identity;
1014
+ }
1015
+ async function hydrateSlackIdentity(token, incoming) {
1016
+ const identity = await resolveSlackUserIdentity(token, incoming);
1017
+ if (!identity) {
1018
+ return {
1019
+ ...incoming,
1020
+ senderVerified: false,
1021
+ actorTrust: { memberType: "unknown", verified: false },
1022
+ };
1023
+ }
1024
+ return {
1025
+ ...incoming,
1026
+ ...(identity.name ? { senderName: identity.name } : {}),
1027
+ ...(identity.email
1028
+ ? { senderEmail: identity.email, senderVerified: true }
1029
+ : { senderVerified: false }),
1030
+ actorTrust: {
1031
+ memberType: identity.memberType,
1032
+ verified: true,
1033
+ },
1034
+ };
1035
+ }
876
1036
  async function hydrateSlackContext(token, incoming) {
877
1037
  const channelId = incoming.platformContext.channelId;
878
1038
  const threadTs = incoming.platformContext.threadTs;
@@ -880,7 +1040,7 @@ async function hydrateSlackContext(token, incoming) {
880
1040
  if (typeof channelId !== "string" || typeof threadTs !== "string") {
881
1041
  return incoming;
882
1042
  }
883
- const [thread, history, pins, conversation, user] = await Promise.all([
1043
+ const [thread, history, pins, conversation, identity] = await Promise.all([
884
1044
  slackJson(token, "conversations.replies", {
885
1045
  channel: channelId,
886
1046
  ts: threadTs,
@@ -894,7 +1054,7 @@ async function hydrateSlackContext(token, incoming) {
894
1054
  }),
895
1055
  slackJson(token, "pins.list", { channel: channelId }),
896
1056
  slackJson(token, "conversations.info", { channel: channelId }),
897
- senderId ? slackJson(token, "users.info", { user: senderId }) : null,
1057
+ senderId ? resolveSlackUserIdentity(token, incoming) : null,
898
1058
  ]);
899
1059
  // Agent View can attach the Slack surface the user is currently viewing to
900
1060
  // a DM. Treat it only as a context hint: Slack requires us to prove the bot
@@ -968,9 +1128,7 @@ async function hydrateSlackContext(token, incoming) {
968
1128
  };
969
1129
  })
970
1130
  : [];
971
- const profile = user?.user?.profile;
972
- const isGuest = user?.user?.is_restricted === true;
973
- const isExternal = user?.user?.is_ultra_restricted === true;
1131
+ const profile = identity;
974
1132
  const isPrivate = conversation?.channel?.is_private === true;
975
1133
  const isExternalShared = conversation?.channel?.is_ext_shared === true;
976
1134
  const isMpim = conversation?.channel?.is_mpim === true;
@@ -1006,19 +1164,20 @@ async function hydrateSlackContext(token, incoming) {
1006
1164
  const hydratedFiles = hydratedMessages.flatMap((message) => message.files ?? []);
1007
1165
  return {
1008
1166
  ...incoming,
1009
- ...(typeof profile?.display_name === "string" && profile.display_name
1010
- ? { senderName: profile.display_name }
1011
- : typeof profile?.real_name === "string" && profile.real_name
1012
- ? { senderName: profile.real_name }
1013
- : {}),
1014
- ...(typeof profile?.email === "string"
1167
+ ...(profile?.name ? { senderName: profile.name } : {}),
1168
+ ...(profile?.email
1015
1169
  ? { senderEmail: profile.email, senderVerified: true }
1016
- : {}),
1170
+ : { senderVerified: false }),
1017
1171
  conversationType,
1018
- actorTrust: {
1019
- memberType: isExternal ? "external" : isGuest ? "guest" : "member",
1020
- verified: true,
1021
- },
1172
+ // Conversation hydration must not promote a caller when users.info was
1173
+ // unavailable. Preserve the result of the earlier identity-only hydration
1174
+ // unless this request independently resolved the Slack user.
1175
+ actorTrust: identity
1176
+ ? { memberType: identity.memberType, verified: true }
1177
+ : (incoming.actorTrust ?? {
1178
+ memberType: "unknown",
1179
+ verified: false,
1180
+ }),
1022
1181
  contextMessages: hydratedMessages,
1023
1182
  ...(hydratedFiles.length ? { files: hydratedFiles.slice(0, 20) } : {}),
1024
1183
  platformContext: {