@vellumai/assistant 0.4.10 → 0.4.12

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 (203) hide show
  1. package/ARCHITECTURE.md +418 -378
  2. package/Dockerfile +1 -1
  3. package/README.md +16 -9
  4. package/package.json +1 -1
  5. package/src/__tests__/account-registry.test.ts +1 -0
  6. package/src/__tests__/actor-token-service.test.ts +1 -0
  7. package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
  8. package/src/__tests__/asset-materialize-tool.test.ts +7 -0
  9. package/src/__tests__/asset-search-tool.test.ts +7 -0
  10. package/src/__tests__/browser-fill-credential.test.ts +1 -0
  11. package/src/__tests__/call-start-guardian-guard.test.ts +1 -0
  12. package/src/__tests__/channel-approval-routes.test.ts +29 -0
  13. package/src/__tests__/channel-guardian.test.ts +2143 -1546
  14. package/src/__tests__/channel-retry-sweep.test.ts +169 -14
  15. package/src/__tests__/claude-code-tool-profiles.test.ts +1 -0
  16. package/src/__tests__/computer-use-tools.test.ts +1 -0
  17. package/src/__tests__/contacts-tools.test.ts +1 -0
  18. package/src/__tests__/conversation-attention-telegram.test.ts +1 -0
  19. package/src/__tests__/credential-policy-validate.test.ts +97 -0
  20. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  21. package/src/__tests__/credential-vault-unit.test.ts +1 -0
  22. package/src/__tests__/credential-vault.test.ts +1 -0
  23. package/src/__tests__/delete-managed-skill-tool.test.ts +1 -0
  24. package/src/__tests__/file-edit-tool.test.ts +1 -0
  25. package/src/__tests__/file-read-tool.test.ts +1 -0
  26. package/src/__tests__/file-write-tool.test.ts +1 -0
  27. package/src/__tests__/followup-tools.test.ts +1 -0
  28. package/src/__tests__/gateway-only-guard.test.ts +1 -1
  29. package/src/__tests__/guardian-control-plane-policy.test.ts +5 -4
  30. package/src/__tests__/guardian-grant-minting.test.ts +3 -0
  31. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +4 -3
  32. package/src/__tests__/guardian-routing-state.test.ts +8 -0
  33. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +75 -61
  34. package/src/__tests__/headless-browser-interactions.test.ts +1 -0
  35. package/src/__tests__/headless-browser-navigate.test.ts +1 -0
  36. package/src/__tests__/headless-browser-read-tools.test.ts +1 -0
  37. package/src/__tests__/headless-browser-snapshot.test.ts +1 -0
  38. package/src/__tests__/host-file-edit-tool.test.ts +1 -0
  39. package/src/__tests__/host-file-read-tool.test.ts +1 -0
  40. package/src/__tests__/host-file-write-tool.test.ts +1 -0
  41. package/src/__tests__/host-shell-tool.test.ts +1 -0
  42. package/src/__tests__/lifecycle-docs-guard.test.ts +207 -0
  43. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -0
  44. package/src/__tests__/media-reuse-story.e2e.test.ts +8 -0
  45. package/src/__tests__/messaging-send-tool.test.ts +1 -0
  46. package/src/__tests__/playbook-execution.test.ts +1 -0
  47. package/src/__tests__/playbook-tools.test.ts +1 -0
  48. package/src/__tests__/registry.test.ts +235 -187
  49. package/src/__tests__/relay-server.test.ts +4 -0
  50. package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -0
  51. package/src/__tests__/schedule-tools.test.ts +1 -0
  52. package/src/__tests__/secret-onetime-send.test.ts +4 -0
  53. package/src/__tests__/secret-scanner-executor.test.ts +2 -0
  54. package/src/__tests__/secure-keys.test.ts +27 -0
  55. package/src/__tests__/send-notification-tool.test.ts +2 -0
  56. package/src/__tests__/session-agent-loop.test.ts +521 -256
  57. package/src/__tests__/session-surfaces-task-progress.test.ts +1 -0
  58. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
  59. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
  60. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
  61. package/src/__tests__/shell-credential-ref.test.ts +1 -0
  62. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -0
  63. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  64. package/src/__tests__/skill-load-tool.test.ts +1 -0
  65. package/src/__tests__/skill-script-runner-host.test.ts +1 -0
  66. package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -0
  67. package/src/__tests__/skill-script-runner.test.ts +1 -0
  68. package/src/__tests__/skill-tool-factory.test.ts +1 -0
  69. package/src/__tests__/skills.test.ts +334 -276
  70. package/src/__tests__/starter-task-flow.test.ts +7 -17
  71. package/src/__tests__/subagent-tools.test.ts +1 -1
  72. package/src/__tests__/swarm-recursion.test.ts +1 -0
  73. package/src/__tests__/swarm-session-integration.test.ts +1 -0
  74. package/src/__tests__/swarm-tool.test.ts +1 -0
  75. package/src/__tests__/task-management-tools.test.ts +1 -0
  76. package/src/__tests__/task-tools.test.ts +1 -0
  77. package/src/__tests__/terminal-tools.test.ts +1 -0
  78. package/src/__tests__/tool-approval-handler.test.ts +2 -2
  79. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
  80. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -0
  81. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
  82. package/src/__tests__/tool-executor-shell-integration.test.ts +1 -0
  83. package/src/__tests__/tool-executor.test.ts +1 -0
  84. package/src/__tests__/trust-context-guards.test.ts +218 -0
  85. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +6 -0
  86. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +6 -0
  87. package/src/__tests__/trusted-contact-multichannel.test.ts +1 -0
  88. package/src/__tests__/trusted-contact-verification.test.ts +1 -0
  89. package/src/__tests__/view-image-tool.test.ts +1 -0
  90. package/src/agent/loop.ts +9 -2
  91. package/src/calls/guardian-dispatch.ts +4 -4
  92. package/src/cli/mcp.ts +183 -3
  93. package/src/config/bundled-skills/agentmail/SKILL.md +4 -4
  94. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +449 -0
  95. package/src/config/bundled-skills/doordash/SKILL.md +171 -0
  96. package/src/config/bundled-skills/doordash/__tests__/doordash-client.test.ts +203 -0
  97. package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +164 -0
  98. package/src/config/bundled-skills/doordash/doordash-cli.ts +1193 -0
  99. package/src/config/bundled-skills/doordash/doordash-entry.ts +22 -0
  100. package/src/config/bundled-skills/doordash/lib/cart-queries.ts +787 -0
  101. package/src/config/bundled-skills/doordash/lib/client.ts +1071 -0
  102. package/src/config/bundled-skills/doordash/lib/order-queries.ts +85 -0
  103. package/src/config/bundled-skills/doordash/lib/queries.ts +28 -0
  104. package/src/config/bundled-skills/doordash/lib/query-extractor.ts +94 -0
  105. package/src/config/bundled-skills/doordash/lib/search-queries.ts +203 -0
  106. package/src/config/bundled-skills/doordash/lib/session.ts +93 -0
  107. package/src/config/bundled-skills/doordash/lib/shared/errors.ts +61 -0
  108. package/src/config/bundled-skills/doordash/lib/shared/ipc.ts +32 -0
  109. package/src/config/bundled-skills/doordash/lib/shared/network-recorder.ts +380 -0
  110. package/src/config/bundled-skills/doordash/lib/shared/platform.ts +35 -0
  111. package/src/config/bundled-skills/doordash/lib/shared/recording-store.ts +43 -0
  112. package/src/config/bundled-skills/doordash/lib/shared/recording-types.ts +49 -0
  113. package/src/config/bundled-skills/doordash/lib/shared/truncate.ts +6 -0
  114. package/src/config/bundled-skills/doordash/lib/store-queries.ts +246 -0
  115. package/src/config/bundled-skills/doordash/lib/types.ts +367 -0
  116. package/src/config/bundled-skills/google-calendar/SKILL.md +4 -5
  117. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +42 -41
  118. package/src/config/bundled-skills/messaging/SKILL.md +59 -42
  119. package/src/config/bundled-skills/messaging/TOOLS.json +2 -2
  120. package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +5 -1
  121. package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +11 -2
  122. package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +10 -3
  123. package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +5 -1
  124. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +5 -1
  125. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -1
  126. package/src/config/bundled-skills/notion/SKILL.md +240 -0
  127. package/src/config/bundled-skills/notion-oauth-setup/SKILL.md +127 -0
  128. package/src/config/bundled-skills/oauth-setup/SKILL.md +144 -0
  129. package/src/config/bundled-skills/phone-calls/SKILL.md +91 -162
  130. package/src/config/bundled-skills/skills-catalog/SKILL.md +32 -29
  131. package/src/config/{vellum-skills → bundled-skills}/sms-setup/SKILL.md +29 -22
  132. package/src/config/{vellum-skills → bundled-skills}/telegram-setup/SKILL.md +17 -14
  133. package/src/config/{vellum-skills → bundled-skills}/twilio-setup/SKILL.md +21 -6
  134. package/src/config/bundled-tool-registry.ts +281 -267
  135. package/src/config/system-prompt.ts +4 -2
  136. package/src/daemon/computer-use-session.ts +1 -0
  137. package/src/daemon/handlers/skills.ts +334 -234
  138. package/src/daemon/ipc-contract/messages.ts +2 -0
  139. package/src/daemon/ipc-contract/surfaces.ts +2 -0
  140. package/src/daemon/lifecycle.ts +358 -221
  141. package/src/daemon/response-tier.ts +2 -0
  142. package/src/daemon/server.ts +453 -193
  143. package/src/daemon/session-agent-loop-handlers.ts +42 -2
  144. package/src/daemon/session-agent-loop.ts +4 -1
  145. package/src/daemon/session-lifecycle.ts +3 -0
  146. package/src/daemon/session-memory.ts +2 -2
  147. package/src/daemon/session-process.ts +1 -0
  148. package/src/daemon/session-runtime-assembly.ts +2 -2
  149. package/src/daemon/session-surfaces.ts +22 -20
  150. package/src/daemon/session-tool-setup.ts +2 -1
  151. package/src/daemon/session.ts +5 -2
  152. package/src/mcp/client.ts +55 -6
  153. package/src/mcp/manager.ts +9 -0
  154. package/src/mcp/mcp-oauth-provider.ts +347 -0
  155. package/src/memory/channel-delivery-store.ts +1 -0
  156. package/src/memory/db-init.ts +4 -0
  157. package/src/memory/delivery-status.ts +43 -0
  158. package/src/memory/guardian-bindings.ts +3 -3
  159. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +108 -0
  160. package/src/memory/migrations/index.ts +1 -0
  161. package/src/memory/migrations/registry.ts +6 -0
  162. package/src/memory/schema.ts +1 -1
  163. package/src/messaging/outreach-classifier.ts +12 -5
  164. package/src/messaging/provider-types.ts +2 -0
  165. package/src/messaging/providers/gmail/adapter.ts +9 -3
  166. package/src/messaging/providers/gmail/client.ts +2 -0
  167. package/src/runtime/actor-trust-resolver.ts +13 -4
  168. package/src/runtime/channel-retry-sweep.ts +31 -14
  169. package/src/runtime/guardian-context-resolver.ts +25 -64
  170. package/src/runtime/guardian-outbound-actions.ts +399 -108
  171. package/src/runtime/guardian-vellum-migration.ts +1 -23
  172. package/src/runtime/guardian-verification-templates.ts +66 -30
  173. package/src/runtime/http-errors.ts +33 -20
  174. package/src/runtime/http-server.ts +706 -291
  175. package/src/runtime/http-types.ts +26 -16
  176. package/src/runtime/local-actor-identity.ts +4 -6
  177. package/src/runtime/middleware/actor-token.ts +2 -8
  178. package/src/runtime/routes/channel-route-shared.ts +0 -1
  179. package/src/runtime/routes/inbound-message-handler.ts +3 -4
  180. package/src/runtime/routes/secret-routes.ts +57 -2
  181. package/src/runtime/routes/surface-action-routes.ts +66 -0
  182. package/src/runtime/routes/trust-rules-routes.ts +140 -0
  183. package/src/runtime/tool-grant-request-helper.ts +1 -1
  184. package/src/security/keychain-to-encrypted-migration.ts +59 -0
  185. package/src/security/secure-keys.ts +17 -0
  186. package/src/skills/frontmatter.ts +9 -7
  187. package/src/tools/apps/executors.ts +2 -1
  188. package/src/tools/credentials/policy-validate.ts +22 -0
  189. package/src/tools/guardian-control-plane-policy.ts +2 -2
  190. package/src/tools/tool-manifest.ts +44 -42
  191. package/src/tools/types.ts +10 -1
  192. package/src/__tests__/skill-mirror-parity.test.ts +0 -176
  193. package/src/config/vellum-skills/catalog.json +0 -63
  194. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +0 -295
  195. package/src/skills/vellum-catalog-remote.ts +0 -166
  196. package/src/tools/skills/vellum-catalog.ts +0 -168
  197. /package/src/config/{vellum-skills → bundled-skills}/chatgpt-import/SKILL.md +0 -0
  198. /package/src/config/{vellum-skills → bundled-skills}/chatgpt-import/TOOLS.json +0 -0
  199. /package/src/config/{vellum-skills → bundled-skills}/deploy-fullstack-vercel/SKILL.md +0 -0
  200. /package/src/config/{vellum-skills → bundled-skills}/document-writer/SKILL.md +0 -0
  201. /package/src/config/{vellum-skills → bundled-skills}/guardian-verify-setup/SKILL.md +0 -0
  202. /package/src/config/{vellum-skills → bundled-skills}/slack-oauth-setup/SKILL.md +0 -0
  203. /package/src/config/{vellum-skills → bundled-skills}/trusted-contacts/SKILL.md +0 -0
@@ -20,6 +20,8 @@ import { canonicalizeInboundIdentity } from '../util/canonicalize-identity.js';
20
20
  import { DAEMON_INTERNAL_ASSISTANT_ID } from './assistant-scope.js';
21
21
  import { getGuardianBinding } from './channel-guardian-service.js';
22
22
 
23
+ export type { GuardianRuntimeContext } from '../daemon/session-runtime-assembly.js';
24
+
23
25
  // ---------------------------------------------------------------------------
24
26
  // Types
25
27
  // ---------------------------------------------------------------------------
@@ -35,8 +37,8 @@ export interface ActorTrustContext {
35
37
  guardianExternalUserId: string;
36
38
  guardianDeliveryChatId: string | null;
37
39
  } | null;
38
- /** Canonical principal ID from the guardian binding. Nullable for backward compatibility — M5 will make this required. */
39
- guardianPrincipalId?: string | null;
40
+ /** Canonical principal ID from the guardian binding. */
41
+ guardianPrincipalId?: string;
40
42
  /** Ingress member record, if any, for this sender. */
41
43
  memberRecord: IngressMember | null;
42
44
  /** Trust classification. */
@@ -184,7 +186,7 @@ export function resolveActorTrust(input: ResolveActorTrustInput): ActorTrustCont
184
186
  return {
185
187
  canonicalSenderId,
186
188
  guardianBindingMatch,
187
- guardianPrincipalId: binding?.guardianPrincipalId ?? undefined,
189
+ guardianPrincipalId: binding?.guardianPrincipalId,
188
190
  memberRecord,
189
191
  trustClass,
190
192
  actorMetadata: {
@@ -203,17 +205,24 @@ export function resolveActorTrust(input: ResolveActorTrustInput): ActorTrustCont
203
205
  /**
204
206
  * Convert an ActorTrustContext into the runtime trust context shape used by
205
207
  * sessions/tooling.
208
+ *
209
+ * This is the single canonical conversion from resolved trust to runtime
210
+ * context. The guardianExternalUserId is canonicalized to handle phone-
211
+ * channel formatting variance (e.g. stored binding vs E.164).
206
212
  */
207
213
  export function toGuardianRuntimeContextFromTrust(
208
214
  ctx: ActorTrustContext,
209
215
  conversationExternalId: string,
210
216
  ): GuardianRuntimeContext {
217
+ const canonicalGuardianExternalUserId = ctx.guardianBindingMatch?.guardianExternalUserId
218
+ ? canonicalizeInboundIdentity(ctx.actorMetadata.channel, ctx.guardianBindingMatch.guardianExternalUserId) ?? undefined
219
+ : undefined;
211
220
  return {
212
221
  sourceChannel: ctx.actorMetadata.channel,
213
222
  trustClass: ctx.trustClass,
214
223
  guardianChatId: ctx.guardianBindingMatch?.guardianDeliveryChatId ??
215
224
  (ctx.trustClass === 'guardian' ? conversationExternalId : undefined),
216
- guardianExternalUserId: ctx.guardianBindingMatch?.guardianExternalUserId,
225
+ guardianExternalUserId: canonicalGuardianExternalUserId,
217
226
  guardianPrincipalId: ctx.guardianPrincipalId,
218
227
  requesterIdentifier: ctx.actorMetadata.identifier,
219
228
  requesterDisplayName: ctx.actorMetadata.displayName,
@@ -15,16 +15,7 @@ const log = getLogger('runtime-http');
15
15
  function parseGuardianRuntimeContext(value: unknown): GuardianRuntimeContext | undefined {
16
16
  if (!value || typeof value !== 'object') return undefined;
17
17
  const raw = value as Record<string, unknown>;
18
- const trustClass = raw.trustClass
19
- ?? (
20
- raw.actorRole === 'guardian'
21
- ? 'guardian'
22
- : raw.actorRole === 'non-guardian'
23
- ? 'trusted_contact'
24
- : raw.actorRole === 'unverified_channel'
25
- ? 'unknown'
26
- : undefined
27
- );
18
+ const trustClass = raw.trustClass;
28
19
  if (
29
20
  trustClass !== 'guardian'
30
21
  && trustClass !== 'trusted_contact'
@@ -46,6 +37,7 @@ function parseGuardianRuntimeContext(value: unknown): GuardianRuntimeContext | u
46
37
  trustClass,
47
38
  guardianChatId: typeof raw.guardianChatId === 'string' ? raw.guardianChatId : undefined,
48
39
  guardianExternalUserId: typeof raw.guardianExternalUserId === 'string' ? raw.guardianExternalUserId : undefined,
40
+ guardianPrincipalId: typeof raw.guardianPrincipalId === 'string' ? raw.guardianPrincipalId : undefined,
49
41
  requesterIdentifier: typeof raw.requesterIdentifier === 'string' ? raw.requesterIdentifier : undefined,
50
42
  requesterDisplayName: typeof raw.requesterDisplayName === 'string' ? raw.requesterDisplayName : undefined,
51
43
  requesterSenderDisplayName: typeof raw.requesterSenderDisplayName === 'string' ? raw.requesterSenderDisplayName : undefined,
@@ -107,7 +99,34 @@ export async function sweepFailedEvents(
107
99
  const assistantId = typeof payload.assistantId === 'string'
108
100
  ? payload.assistantId
109
101
  : undefined;
110
- const guardianContext = parseGuardianRuntimeContext(payload.guardianCtx);
102
+ const parsedGuardianContext = parseGuardianRuntimeContext(payload.guardianCtx);
103
+
104
+ // If the stored payload had guardian context data but it couldn't be parsed
105
+ // into a valid canonical shape (e.g., legacy actorRole-only payloads without
106
+ // trustClass), fail the event deterministically rather than processing it
107
+ // without guardian context. Without this check, the downstream default of
108
+ // `guardianTrustClass ?? 'guardian'` would silently escalate privileges.
109
+ if (payload.guardianCtx && !parsedGuardianContext) {
110
+ log.warn(
111
+ { eventId: event.id },
112
+ 'Stored guardianCtx could not be parsed into canonical form; marking event as failed to prevent privilege escalation',
113
+ );
114
+ channelDeliveryStore.markRetryableFailure(
115
+ event.id,
116
+ 'Unparseable guardian context in stored payload — refusing to process without trust classification',
117
+ );
118
+ continue;
119
+ }
120
+
121
+ // When guardianCtx is entirely absent (pre-guardian events or events stored
122
+ // before trust context was added), synthesize an explicit 'unknown' context.
123
+ // This ensures replay never proceeds without an explicit trust classification
124
+ // — downstream defaults like `guardianTrustClass ?? 'guardian'` would
125
+ // otherwise grant guardian-level tool access to unclassified events.
126
+ const guardianContext: GuardianRuntimeContext = parsedGuardianContext ?? {
127
+ sourceChannel,
128
+ trustClass: 'unknown',
129
+ };
111
130
 
112
131
  const metadataHintsRaw = sourceMetadata?.hints;
113
132
  const metadataHints = Array.isArray(metadataHintsRaw)
@@ -130,9 +149,7 @@ export async function sweepFailedEvents(
130
149
  },
131
150
  assistantId,
132
151
  guardianContext,
133
- isInteractive: guardianContext
134
- ? resolveRoutingStateFromRuntime(guardianContext).promptWaitingAllowed
135
- : false,
152
+ isInteractive: resolveRoutingStateFromRuntime(guardianContext).promptWaitingAllowed,
136
153
  },
137
154
  sourceChannel,
138
155
  sourceInterface,
@@ -1,17 +1,20 @@
1
1
  /**
2
2
  * Shared inbound trust resolution for channel actors.
3
3
  *
4
- * This module provides a compact route-level shape used by channel routes
5
- * while delegating canonical classification to the unified actor trust
6
- * resolver.
4
+ * GuardianContext is a type alias for GuardianRuntimeContext the
5
+ * canonical runtime trust context used by sessions, tooling, and channel
6
+ * routes. This module re-exports the alias and provides routing-state
7
+ * helpers that operate on the canonical type.
8
+ *
9
+ * Trust resolution itself lives in actor-trust-resolver.ts; the resolved
10
+ * ActorTrustContext is converted to GuardianRuntimeContext via
11
+ * toGuardianRuntimeContextFromTrust.
7
12
  */
8
- import type { ChannelId } from '../channels/types.js';
9
13
  import type { GuardianRuntimeContext } from '../daemon/session-runtime-assembly.js';
10
- import { canonicalizeInboundIdentity } from '../util/canonicalize-identity.js';
11
14
  import {
12
- type DenialReason,
13
15
  resolveActorTrust,
14
16
  type ResolveActorTrustInput,
17
+ toGuardianRuntimeContextFromTrust,
15
18
  type TrustClass,
16
19
  } from './actor-trust-resolver.js';
17
20
  export type { DenialReason } from './actor-trust-resolver.js';
@@ -19,50 +22,28 @@ export type { DenialReason } from './actor-trust-resolver.js';
19
22
  /** Trust classification used by route-level channel logic. */
20
23
  export type ActorTrustClass = TrustClass;
21
24
 
22
- /** Guardian actor context used by route-level approval logic. */
23
- export interface GuardianContext {
24
- trustClass: ActorTrustClass;
25
- guardianChatId?: string;
26
- guardianExternalUserId?: string;
27
- /** Canonical principal ID from the guardian binding. Nullable for backward compatibility — M5 will make this required. */
28
- guardianPrincipalId?: string | null;
29
- requesterIdentifier?: string;
30
- requesterDisplayName?: string;
31
- requesterSenderDisplayName?: string;
32
- requesterMemberDisplayName?: string;
33
- requesterExternalUserId?: string;
34
- requesterChatId?: string;
35
- memberStatus?: string;
36
- memberPolicy?: string;
37
- denialReason?: DenialReason;
38
- }
25
+ /**
26
+ * GuardianContext is the canonical runtime trust context.
27
+ *
28
+ * Previously this was a separate interface with extra fields (memberStatus,
29
+ * memberPolicy). Those fields were only needed for InboundActorContext
30
+ * construction, which now sources them directly from ActorTrustContext.
31
+ * This alias unifies the two shapes and removes the redundant conversion
32
+ * layer.
33
+ */
34
+ export type GuardianContext = GuardianRuntimeContext;
39
35
 
40
36
  export type ResolveGuardianContextInput = ResolveActorTrustInput;
41
37
 
42
38
  /**
43
39
  * Resolve route-level trust context from canonical identity state.
40
+ *
41
+ * Delegates to resolveActorTrust for classification, then converts to
42
+ * the canonical GuardianRuntimeContext via toGuardianRuntimeContextFromTrust.
44
43
  */
45
44
  export function resolveGuardianContext(input: ResolveGuardianContextInput): GuardianContext {
46
45
  const trust = resolveActorTrust(input);
47
- const canonicalGuardianExternalUserId = trust.guardianBindingMatch?.guardianExternalUserId
48
- ? canonicalizeInboundIdentity(input.sourceChannel, trust.guardianBindingMatch.guardianExternalUserId) ?? undefined
49
- : undefined;
50
- return {
51
- trustClass: trust.trustClass,
52
- guardianChatId: trust.guardianBindingMatch?.guardianDeliveryChatId ??
53
- (trust.trustClass === 'guardian' ? input.conversationExternalId : undefined),
54
- guardianExternalUserId: canonicalGuardianExternalUserId,
55
- guardianPrincipalId: trust.guardianPrincipalId,
56
- requesterIdentifier: trust.actorMetadata.identifier,
57
- requesterDisplayName: trust.actorMetadata.displayName,
58
- requesterSenderDisplayName: trust.actorMetadata.senderDisplayName,
59
- requesterMemberDisplayName: trust.actorMetadata.memberDisplayName,
60
- requesterExternalUserId: trust.canonicalSenderId ?? undefined,
61
- requesterChatId: input.conversationExternalId,
62
- memberStatus: trust.memberRecord?.status ?? undefined,
63
- memberPolicy: trust.memberRecord?.policy ?? undefined,
64
- denialReason: trust.denialReason,
65
- };
46
+ return toGuardianRuntimeContextFromTrust(trust, input.conversationExternalId);
66
47
  }
67
48
 
68
49
  // ---------------------------------------------------------------------------
@@ -102,7 +83,7 @@ export interface RoutingState {
102
83
  * Trusted contacts are only interactive when a guardian binding exists
103
84
  * to receive approval notifications. Unknown actors are never interactive.
104
85
  */
105
- export function resolveRoutingState(ctx: GuardianContext): RoutingState {
86
+ export function resolveRoutingState(ctx: Pick<GuardianRuntimeContext, 'trustClass' | 'guardianExternalUserId'>): RoutingState {
106
87
  const isGuardian = ctx.trustClass === 'guardian';
107
88
  const isTrustedContact = ctx.trustClass === 'trusted_contact';
108
89
 
@@ -141,25 +122,5 @@ export function resolveRoutingState(ctx: GuardianContext): RoutingState {
141
122
  * (the shape persisted in stored payloads and used by the retry sweep).
142
123
  */
143
124
  export function resolveRoutingStateFromRuntime(ctx: GuardianRuntimeContext): RoutingState {
144
- return resolveRoutingState({
145
- trustClass: ctx.trustClass,
146
- guardianExternalUserId: ctx.guardianExternalUserId,
147
- });
148
- }
149
-
150
- export function toGuardianRuntimeContext(sourceChannel: ChannelId, ctx: GuardianContext): GuardianRuntimeContext {
151
- return {
152
- sourceChannel,
153
- trustClass: ctx.trustClass,
154
- guardianChatId: ctx.guardianChatId,
155
- guardianExternalUserId: ctx.guardianExternalUserId,
156
- guardianPrincipalId: ctx.guardianPrincipalId,
157
- requesterIdentifier: ctx.requesterIdentifier,
158
- requesterDisplayName: ctx.requesterDisplayName,
159
- requesterSenderDisplayName: ctx.requesterSenderDisplayName,
160
- requesterMemberDisplayName: ctx.requesterMemberDisplayName,
161
- requesterExternalUserId: ctx.requesterExternalUserId,
162
- requesterChatId: ctx.requesterChatId,
163
- denialReason: ctx.denialReason,
164
- };
125
+ return resolveRoutingState(ctx);
165
126
  }