@vellumai/assistant 0.4.49 → 0.4.50

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 (239) hide show
  1. package/ARCHITECTURE.md +24 -33
  2. package/README.md +3 -3
  3. package/docs/architecture/memory.md +180 -119
  4. package/package.json +2 -2
  5. package/src/__tests__/agent-loop.test.ts +3 -1
  6. package/src/__tests__/anthropic-provider.test.ts +114 -23
  7. package/src/__tests__/approval-cascade.test.ts +1 -15
  8. package/src/__tests__/approval-routes-http.test.ts +2 -0
  9. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  10. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  11. package/src/__tests__/checker.test.ts +13 -0
  12. package/src/__tests__/config-schema.test.ts +1 -68
  13. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  14. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  15. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  16. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  17. package/src/__tests__/credential-vault-unit.test.ts +4 -0
  18. package/src/__tests__/credential-vault.test.ts +13 -1
  19. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  20. package/src/__tests__/date-context.test.ts +93 -77
  21. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  22. package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
  23. package/src/__tests__/history-repair.test.ts +245 -0
  24. package/src/__tests__/host-cu-proxy.test.ts +165 -3
  25. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  26. package/src/__tests__/invite-redemption-service.test.ts +65 -1
  27. package/src/__tests__/keychain-broker-client.test.ts +4 -4
  28. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  29. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  30. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  31. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  32. package/src/__tests__/memory-regressions.test.ts +477 -2841
  33. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  34. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  35. package/src/__tests__/mime-builder.test.ts +28 -0
  36. package/src/__tests__/native-web-search.test.ts +1 -0
  37. package/src/__tests__/oauth-cli.test.ts +572 -5
  38. package/src/__tests__/oauth-store.test.ts +120 -6
  39. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  40. package/src/__tests__/registry.test.ts +0 -1
  41. package/src/__tests__/relay-server.test.ts +46 -1
  42. package/src/__tests__/schedule-tools.test.ts +32 -0
  43. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  44. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  45. package/src/__tests__/secure-keys.test.ts +7 -2
  46. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  47. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  48. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  49. package/src/__tests__/session-agent-loop.test.ts +19 -15
  50. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  51. package/src/__tests__/session-error.test.ts +124 -2
  52. package/src/__tests__/session-history-web-search.test.ts +918 -0
  53. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  54. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  55. package/src/__tests__/session-queue.test.ts +37 -27
  56. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  57. package/src/__tests__/session-slash-known.test.ts +1 -15
  58. package/src/__tests__/session-slash-queue.test.ts +1 -15
  59. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  60. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  61. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  62. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  63. package/src/__tests__/skills-install-extract.test.ts +93 -0
  64. package/src/__tests__/skillssh-registry.test.ts +451 -0
  65. package/src/__tests__/trust-store.test.ts +15 -0
  66. package/src/__tests__/voice-invite-redemption.test.ts +32 -1
  67. package/src/agent/ax-tree-compaction.test.ts +51 -0
  68. package/src/agent/loop.ts +39 -12
  69. package/src/approvals/AGENTS.md +1 -1
  70. package/src/approvals/guardian-request-resolvers.ts +14 -2
  71. package/src/bundler/compiler-tools.ts +66 -2
  72. package/src/calls/call-domain.ts +132 -0
  73. package/src/calls/call-store.ts +6 -0
  74. package/src/calls/relay-server.ts +43 -5
  75. package/src/calls/relay-setup-router.ts +17 -1
  76. package/src/calls/twilio-config.ts +1 -1
  77. package/src/calls/types.ts +3 -1
  78. package/src/cli/commands/doctor.ts +4 -3
  79. package/src/cli/commands/mcp.ts +46 -59
  80. package/src/cli/commands/memory.ts +16 -165
  81. package/src/cli/commands/oauth/apps.ts +31 -2
  82. package/src/cli/commands/oauth/connections.ts +431 -97
  83. package/src/cli/commands/oauth/providers.ts +15 -1
  84. package/src/cli/commands/sessions.ts +5 -2
  85. package/src/cli/commands/skills.ts +173 -1
  86. package/src/cli/http-client.ts +0 -20
  87. package/src/cli/main-screen.tsx +2 -2
  88. package/src/cli/program.ts +5 -6
  89. package/src/cli.ts +4 -10
  90. package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
  91. package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
  92. package/src/config/bundled-tool-registry.ts +2 -5
  93. package/src/config/schema.ts +1 -12
  94. package/src/config/schemas/memory-lifecycle.ts +0 -9
  95. package/src/config/schemas/memory-processing.ts +0 -180
  96. package/src/config/schemas/memory-retrieval.ts +32 -104
  97. package/src/config/schemas/memory.ts +0 -10
  98. package/src/config/types.ts +0 -4
  99. package/src/context/window-manager.ts +4 -1
  100. package/src/daemon/config-watcher.ts +61 -3
  101. package/src/daemon/daemon-control.ts +1 -1
  102. package/src/daemon/date-context.ts +114 -31
  103. package/src/daemon/handlers/sessions.ts +18 -13
  104. package/src/daemon/handlers/skills.ts +20 -1
  105. package/src/daemon/history-repair.ts +72 -8
  106. package/src/daemon/host-cu-proxy.ts +55 -26
  107. package/src/daemon/lifecycle.ts +31 -3
  108. package/src/daemon/mcp-reload-service.ts +2 -2
  109. package/src/daemon/message-types/computer-use.ts +1 -12
  110. package/src/daemon/message-types/memory.ts +4 -16
  111. package/src/daemon/message-types/messages.ts +1 -0
  112. package/src/daemon/message-types/sessions.ts +4 -0
  113. package/src/daemon/server.ts +12 -1
  114. package/src/daemon/session-agent-loop-handlers.ts +38 -0
  115. package/src/daemon/session-agent-loop.ts +334 -48
  116. package/src/daemon/session-error.ts +89 -6
  117. package/src/daemon/session-history.ts +17 -7
  118. package/src/daemon/session-media-retry.ts +6 -2
  119. package/src/daemon/session-memory.ts +69 -149
  120. package/src/daemon/session-process.ts +10 -1
  121. package/src/daemon/session-runtime-assembly.ts +49 -19
  122. package/src/daemon/session-surfaces.ts +4 -1
  123. package/src/daemon/session-tool-setup.ts +7 -1
  124. package/src/daemon/session.ts +12 -2
  125. package/src/instrument.ts +61 -1
  126. package/src/memory/admin.ts +2 -191
  127. package/src/memory/canonical-guardian-store.ts +38 -2
  128. package/src/memory/conversation-crud.ts +0 -33
  129. package/src/memory/conversation-queries.ts +22 -3
  130. package/src/memory/db-init.ts +28 -0
  131. package/src/memory/embedding-backend.ts +84 -8
  132. package/src/memory/embedding-types.ts +9 -1
  133. package/src/memory/indexer.ts +7 -46
  134. package/src/memory/items-extractor.ts +274 -76
  135. package/src/memory/job-handlers/backfill.ts +2 -127
  136. package/src/memory/job-handlers/cleanup.ts +2 -16
  137. package/src/memory/job-handlers/extraction.ts +2 -138
  138. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  139. package/src/memory/job-handlers/summarization.ts +3 -148
  140. package/src/memory/job-utils.ts +21 -59
  141. package/src/memory/jobs-store.ts +1 -159
  142. package/src/memory/jobs-worker.ts +9 -52
  143. package/src/memory/migrations/104-core-indexes.ts +3 -3
  144. package/src/memory/migrations/149-oauth-tables.ts +2 -0
  145. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  146. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  147. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  148. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  149. package/src/memory/migrations/154-drop-fts.ts +20 -0
  150. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  151. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  152. package/src/memory/migrations/index.ts +7 -0
  153. package/src/memory/qdrant-client.ts +148 -51
  154. package/src/memory/raw-query.ts +1 -1
  155. package/src/memory/retriever.test.ts +294 -273
  156. package/src/memory/retriever.ts +421 -645
  157. package/src/memory/schema/calls.ts +2 -0
  158. package/src/memory/schema/memory-core.ts +3 -48
  159. package/src/memory/schema/oauth.ts +2 -0
  160. package/src/memory/search/formatting.ts +263 -176
  161. package/src/memory/search/lexical.ts +1 -254
  162. package/src/memory/search/ranking.ts +0 -455
  163. package/src/memory/search/semantic.ts +100 -14
  164. package/src/memory/search/staleness.ts +47 -0
  165. package/src/memory/search/tier-classifier.ts +21 -0
  166. package/src/memory/search/types.ts +15 -77
  167. package/src/memory/task-memory-cleanup.ts +4 -6
  168. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  169. package/src/oauth/byo-connection.test.ts +8 -1
  170. package/src/oauth/oauth-store.ts +113 -27
  171. package/src/oauth/seed-providers.ts +6 -0
  172. package/src/oauth/token-persistence.ts +11 -3
  173. package/src/permissions/defaults.ts +1 -0
  174. package/src/permissions/trust-store.ts +23 -1
  175. package/src/playbooks/playbook-compiler.ts +1 -1
  176. package/src/prompts/system-prompt.ts +18 -2
  177. package/src/providers/anthropic/client.ts +56 -126
  178. package/src/providers/types.ts +7 -1
  179. package/src/runtime/AGENTS.md +9 -0
  180. package/src/runtime/auth/route-policy.ts +6 -3
  181. package/src/runtime/guardian-reply-router.ts +24 -22
  182. package/src/runtime/http-server.ts +2 -2
  183. package/src/runtime/invite-redemption-service.ts +19 -1
  184. package/src/runtime/invite-service.ts +25 -0
  185. package/src/runtime/pending-interactions.ts +2 -2
  186. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  187. package/src/runtime/routes/conversation-routes.ts +9 -1
  188. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  189. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  190. package/src/runtime/routes/memory-item-routes.ts +503 -0
  191. package/src/runtime/routes/session-management-routes.ts +3 -3
  192. package/src/runtime/routes/settings-routes.ts +2 -2
  193. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  194. package/src/runtime/routes/workspace-routes.ts +2 -1
  195. package/src/security/keychain-broker-client.ts +17 -4
  196. package/src/security/secure-keys.ts +25 -3
  197. package/src/security/token-manager.ts +36 -36
  198. package/src/skills/catalog-install.ts +74 -18
  199. package/src/skills/skillssh-registry.ts +503 -0
  200. package/src/tools/assets/search.ts +5 -1
  201. package/src/tools/computer-use/definitions.ts +0 -10
  202. package/src/tools/computer-use/registry.ts +1 -1
  203. package/src/tools/credentials/vault.ts +1 -3
  204. package/src/tools/memory/definitions.ts +4 -13
  205. package/src/tools/memory/handlers.test.ts +83 -103
  206. package/src/tools/memory/handlers.ts +50 -85
  207. package/src/tools/schedule/create.ts +8 -1
  208. package/src/tools/schedule/update.ts +8 -1
  209. package/src/tools/skills/load.ts +25 -2
  210. package/src/__tests__/clarification-resolver.test.ts +0 -193
  211. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  212. package/src/__tests__/conflict-policy.test.ts +0 -269
  213. package/src/__tests__/conflict-store.test.ts +0 -372
  214. package/src/__tests__/contradiction-checker.test.ts +0 -361
  215. package/src/__tests__/entity-extractor.test.ts +0 -211
  216. package/src/__tests__/entity-search.test.ts +0 -1117
  217. package/src/__tests__/profile-compiler.test.ts +0 -392
  218. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  219. package/src/__tests__/session-profile-injection.test.ts +0 -557
  220. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  221. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  222. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  223. package/src/daemon/session-conflict-gate.ts +0 -167
  224. package/src/daemon/session-dynamic-profile.ts +0 -77
  225. package/src/memory/clarification-resolver.ts +0 -417
  226. package/src/memory/conflict-intent.ts +0 -205
  227. package/src/memory/conflict-policy.ts +0 -127
  228. package/src/memory/conflict-store.ts +0 -410
  229. package/src/memory/contradiction-checker.ts +0 -508
  230. package/src/memory/entity-extractor.ts +0 -535
  231. package/src/memory/format-recall.ts +0 -47
  232. package/src/memory/fts-reconciler.ts +0 -165
  233. package/src/memory/job-handlers/conflict.ts +0 -200
  234. package/src/memory/profile-compiler.ts +0 -195
  235. package/src/memory/recall-cache.ts +0 -117
  236. package/src/memory/search/entity.ts +0 -535
  237. package/src/memory/search/query-expansion.test.ts +0 -70
  238. package/src/memory/search/query-expansion.ts +0 -118
  239. package/src/runtime/routes/mcp-routes.ts +0 -20
@@ -2,7 +2,7 @@
2
2
  * Route handlers for the brain graph visualization endpoint.
3
3
  *
4
4
  * Queries the memory database to return a knowledge graph shaped for brain-lobe
5
- * visualization, with entities mapped to brain regions based on their type.
5
+ * visualization, with memory items mapped to brain regions based on their kind.
6
6
  */
7
7
 
8
8
  import { readFileSync } from "node:fs";
@@ -11,65 +11,23 @@ import { join } from "node:path";
11
11
  import { count } from "drizzle-orm";
12
12
 
13
13
  import { getDb } from "../../memory/db.js";
14
- import {
15
- memoryEntities,
16
- memoryEntityRelations,
17
- memoryItems,
18
- } from "../../memory/schema.js";
14
+ import { memoryItems } from "../../memory/schema.js";
19
15
  import { resolveBundledDir } from "../../util/bundled-asset.js";
20
16
  import type { RouteDefinition } from "../http-router.js";
21
17
 
22
- function getLobeRegion(entityType: string): string {
23
- switch (entityType) {
24
- case "person":
25
- case "organization":
26
- return "right-social";
27
- case "project":
28
- case "company":
29
- return "left-planning";
30
- case "tool":
31
- return "left-technical";
32
- case "concept":
33
- return "right-creative";
34
- case "location":
35
- return "right-spatial";
36
- default:
37
- return "center";
38
- }
39
- }
40
-
41
- function getEntityColor(entityType: string): string {
42
- switch (entityType) {
43
- case "person":
44
- return "#22c55e";
45
- case "project":
46
- return "#f97316";
47
- case "tool":
48
- return "#06b6d4";
49
- case "company":
50
- return "#a855f7";
51
- case "organization":
52
- return "#a855f7";
53
- case "concept":
54
- return "#eab308";
55
- case "location":
56
- return "#14b8a6";
57
- default:
58
- return "#94a3b8";
59
- }
60
- }
61
-
62
18
  function getMemoryKindColor(kind: string): string {
63
19
  switch (kind) {
64
- case "profile":
20
+ case "identity":
65
21
  return "#8b5cf6";
66
22
  case "preference":
67
23
  return "#3b82f6";
24
+ case "project":
25
+ return "#10b981";
26
+ case "decision":
27
+ return "#f59e0b";
68
28
  case "constraint":
69
29
  return "#ef4444";
70
- case "instruction":
71
- return "#f59e0b";
72
- case "style":
30
+ case "event":
73
31
  return "#ec4899";
74
32
  default:
75
33
  return "#94a3b8";
@@ -80,27 +38,6 @@ export function handleGetBrainGraph(): Response {
80
38
  try {
81
39
  const db = getDb();
82
40
 
83
- const entityRows = db
84
- .select({
85
- id: memoryEntities.id,
86
- name: memoryEntities.name,
87
- type: memoryEntities.type,
88
- mentionCount: memoryEntities.mentionCount,
89
- firstSeenAt: memoryEntities.firstSeenAt,
90
- lastSeenAt: memoryEntities.lastSeenAt,
91
- })
92
- .from(memoryEntities)
93
- .all();
94
-
95
- const relationRows = db
96
- .select({
97
- sourceEntityId: memoryEntityRelations.sourceEntityId,
98
- targetEntityId: memoryEntityRelations.targetEntityId,
99
- relation: memoryEntityRelations.relation,
100
- })
101
- .from(memoryEntityRelations)
102
- .all();
103
-
104
41
  const kindCountRows = db
105
42
  .select({
106
43
  kind: memoryItems.kind,
@@ -110,23 +47,6 @@ export function handleGetBrainGraph(): Response {
110
47
  .groupBy(memoryItems.kind)
111
48
  .all();
112
49
 
113
- const entities = entityRows.map((entity) => ({
114
- id: entity.id,
115
- name: entity.name,
116
- type: entity.type,
117
- lobeRegion: getLobeRegion(entity.type),
118
- color: getEntityColor(entity.type),
119
- mentionCount: entity.mentionCount,
120
- firstSeenAt: entity.firstSeenAt,
121
- lastSeenAt: entity.lastSeenAt,
122
- }));
123
-
124
- const relations = relationRows.map((rel) => ({
125
- sourceId: rel.sourceEntityId,
126
- targetId: rel.targetEntityId,
127
- relation: rel.relation,
128
- }));
129
-
130
50
  const memorySummary = kindCountRows.map((row) => ({
131
51
  kind: row.kind,
132
52
  count: row.count,
@@ -139,8 +59,8 @@ export function handleGetBrainGraph(): Response {
139
59
  );
140
60
 
141
61
  return Response.json({
142
- entities,
143
- relations,
62
+ entities: [],
63
+ relations: [],
144
64
  memorySummary,
145
65
  totalKnowledgeCount,
146
66
  generatedAt: new Date().toISOString(),
@@ -648,9 +648,17 @@ export async function handleSendMessage(
648
648
  session.setHostFileProxy(fileProxy);
649
649
  }
650
650
  if (!session.isProcessing() || !session.hostCuProxy) {
651
- const cuProxy = new HostCuProxy(onEvent);
651
+ const cuProxy = new HostCuProxy(onEvent, (requestId) => {
652
+ pendingInteractions.resolve(requestId);
653
+ });
652
654
  session.setHostCuProxy(cuProxy);
653
655
  }
656
+ // Only preactivate CU when the session is idle — if the session is
657
+ // processing, this message will be queued and preactivation is deferred
658
+ // to dequeue time in drainQueueImpl to avoid mutating in-flight turn state.
659
+ if (!session.isProcessing()) {
660
+ session.addPreactivatedSkillId("computer-use");
661
+ }
654
662
  } else if (!session.isProcessing()) {
655
663
  session.setHostBashProxy(undefined);
656
664
  session.setHostFileProxy(undefined);
@@ -334,7 +334,7 @@ export async function enforceIngressAcl(
334
334
  dmCallbackUrl,
335
335
  {
336
336
  chatId: senderUserId,
337
- text: "I've notified the owner. They'll share a verification code with you if they approve access. You can reply with the code here.",
337
+ text: "I've notified the owner that you'd like to chat with me. If they approve your request, they'll share a 6-digit verification code with you. You can reply with the code here.",
338
338
  assistantId,
339
339
  },
340
340
  mintBearerToken(),
@@ -423,11 +423,12 @@ export async function enforceIngressAcl(
423
423
 
424
424
  if (resolvedMember) {
425
425
  if (resolvedMember.channel.status !== "active") {
426
+ const isBlockedMember = resolvedMember.channel.status === "blocked";
426
427
  // Same bypass logic as the no-member branch: verification codes and
427
- // bootstrap commands must pass through even when the member record is
428
- // revoked/blocked otherwise the user can never re-verify.
428
+ // bootstrap commands must pass through for re-verifiable states
429
+ // (pending/revoked), but never for blocked members.
429
430
  let denyInactiveMember = true;
430
- if (isGuardianVerifyCode) {
431
+ if (!isBlockedMember && isGuardianVerifyCode) {
431
432
  const hasPendingChallenge = !!getPendingSession(sourceChannel);
432
433
  const hasActiveOutboundSession = !!findActiveSession(sourceChannel);
433
434
  if (hasPendingChallenge || hasActiveOutboundSession) {
@@ -444,7 +445,7 @@ export async function enforceIngressAcl(
444
445
  );
445
446
  }
446
447
  }
447
- if (isBootstrapCommand) {
448
+ if (!isBlockedMember && isBootstrapCommand) {
448
449
  const bootstrapPayload = (
449
450
  rawCommandIntentForAcl as Record<string, unknown>
450
451
  ).payload as string;
@@ -471,9 +472,11 @@ export async function enforceIngressAcl(
471
472
  }
472
473
 
473
474
  // ── Invite token intercept (inactive member) ──
474
- // Same as the non-member branch: invite tokens can reactivate
475
- // revoked/pending members without requiring guardian approval.
476
- if (inviteToken && denyInactiveMember) {
475
+ // Invite tokens can reactivate revoked/pending members without
476
+ // requiring guardian approval, but blocked members are excluded so
477
+ // they are short-circuited at the ACL layer rather than entering the
478
+ // redemption path.
479
+ if (!isBlockedMember && inviteToken && denyInactiveMember) {
477
480
  const inviteResult = await handleInviteTokenIntercept({
478
481
  rawToken: inviteToken,
479
482
  sourceChannel,
@@ -496,9 +499,15 @@ export async function enforceIngressAcl(
496
499
  }
497
500
 
498
501
  // ── 6-digit invite code intercept (inactive member) ──
499
- // Same as the non-member branch: codes can reactivate revoked/pending
500
- // members. Non-matching codes fall through to normal processing.
501
- if (denyInactiveMember && /^\d{6}$/.test(trimmedContent)) {
502
+ // Codes can reactivate revoked/pending members; non-matching codes
503
+ // fall through. Blocked members are excluded here for consistency —
504
+ // the redemption service would reject them anyway, but early exit
505
+ // avoids unnecessary work.
506
+ if (
507
+ !isBlockedMember &&
508
+ denyInactiveMember &&
509
+ /^\d{6}$/.test(trimmedContent)
510
+ ) {
502
511
  const codeInterceptResult = await handleInviteCodeIntercept({
503
512
  code: trimmedContent,
504
513
  sourceChannel,
@@ -579,7 +588,7 @@ export async function enforceIngressAcl(
579
588
  dmCallbackUrl,
580
589
  {
581
590
  chatId: senderUserId,
582
- text: "I've notified the owner. They'll share a verification code with you if they approve access. You can reply with the code here.",
591
+ text: "I've notified the owner that you'd like to chat with me. If they approve your request, they'll share a 6-digit verification code with you. You can reply with the code here.",
583
592
  assistantId,
584
593
  },
585
594
  mintBearerToken(),