@indexnetwork/protocol 6.6.5-rc.391.1 → 6.7.0-rc.392.1

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.
@@ -152,6 +152,19 @@ export function createEnrichmentTools(defineTool, deps) {
152
152
  return;
153
153
  await mergeUserSocials(seed.socials);
154
154
  }
155
+ async function markApprovedProfileConfirmed(context) {
156
+ const latestUser = await userDb.getUser();
157
+ const currentOnboarding = latestUser?.onboarding ?? context.user.onboarding ?? {};
158
+ await userDb.updateUser({
159
+ onboarding: {
160
+ ...currentOnboarding,
161
+ profileConfirmedAt: currentOnboarding.profileConfirmedAt ?? new Date().toISOString(),
162
+ currentStep: currentOnboarding.completedAt
163
+ ? currentOnboarding.currentStep ?? 'complete'
164
+ : 'first_signal',
165
+ },
166
+ });
167
+ }
155
168
  function buildProfileInput(parts) {
156
169
  const lines = [];
157
170
  if (parts.name)
@@ -600,6 +613,7 @@ export function createEnrichmentTools(defineTool, deps) {
600
613
  const profile = { ...query.draft, userId: context.userId };
601
614
  await userDb.saveProfile({ userId: context.userId, identity: profile.identity, context: profile.narrative?.context ?? '' });
602
615
  await persistApprovedProfileContext(profile, user, focusedNetworkId(context));
616
+ await markApprovedProfileConfirmed(context);
603
617
  const decomposeLogLabel = context.isMcp
604
618
  ? 'Approved draft premise decomposition failed'
605
619
  : 'Approved draft premise decomposition failed (web)';
@@ -636,6 +650,7 @@ export function createEnrichmentTools(defineTool, deps) {
636
650
  },
637
651
  };
638
652
  await persistApprovedProfileContext(rawProfile, user, focusedNetworkId(context));
653
+ await markApprovedProfileConfirmed(context);
639
654
  const _confirmTraceEmitter = requestContext.getStore()?.traceEmitter;
640
655
  const _confirmGraphStart = Date.now();
641
656
  _confirmTraceEmitter?.({ type: "graph_start", name: "enrichment" });
@@ -826,6 +841,7 @@ export function createEnrichmentTools(defineTool, deps) {
826
841
  if (result.error)
827
842
  return error(result.error);
828
843
  if (result.profile) {
844
+ await markApprovedProfileConfirmed(context);
829
845
  return success({
830
846
  created: true,
831
847
  message: "Profile saved.",
@@ -873,6 +889,8 @@ export function createEnrichmentTools(defineTool, deps) {
873
889
  return error(result.error);
874
890
  }
875
891
  if (result.profile) {
892
+ if (isOnboarding && query.confirm)
893
+ await markApprovedProfileConfirmed(context);
876
894
  return success({
877
895
  created: true,
878
896
  message: "Profile created/updated with the information you provided.",
@@ -886,6 +904,8 @@ export function createEnrichmentTools(defineTool, deps) {
886
904
  _graphTimings: [{ name: 'enrichment', durationMs: _bioProfileGraphMs, agents: result.agentTimings ?? [] }],
887
905
  });
888
906
  }
907
+ if (isOnboarding && query.confirm)
908
+ await markApprovedProfileConfirmed(context);
889
909
  return success({
890
910
  created: true,
891
911
  message: "Profile created/updated with the information you provided.",
@@ -914,6 +934,8 @@ export function createEnrichmentTools(defineTool, deps) {
914
934
  return error(result.error);
915
935
  }
916
936
  if (result.profile) {
937
+ if (isOnboarding && query.confirm)
938
+ await markApprovedProfileConfirmed(context);
917
939
  return success({
918
940
  created: true,
919
941
  message: "Profile generated from your account data.",
@@ -1131,31 +1153,55 @@ export function createEnrichmentTools(defineTool, deps) {
1131
1153
  });
1132
1154
  const completeOnboarding = defineTool({
1133
1155
  name: "complete_onboarding",
1134
- description: "Marks the user's onboarding as complete, unlocking full platform access. This is the final step in the new-user setup flow.\n\n" +
1135
- "**Prerequisites:** The user must have a confirmed profile AND at least one active intent/signal. The profile must be shown to the user and explicitly approved " +
1136
- "(said 'yes', 'looks good', 'that's right', or similar). The first signal must be persisted before this tool is called; MCP/onboarding agents should call create_intent(..., autoApprove=true).\n\n" +
1137
- "**What happens:** Validates that the confirmed profile and first active intent exist, then sets completedAt timestamp on the user's onboarding record.\n\n" +
1138
- "**Workflow:** create_user_context() -> user confirms preview -> create_user_context(confirm=true) -> create_intent(..., autoApprove=true) -> complete_onboarding()\n\n" +
1139
- "**Returns:** Confirmation that onboarding is complete. No parameters needed.",
1140
- querySchema: z.object({}),
1141
- handler: async ({ context }) => {
1142
- const currentOnboarding = context.user.onboarding ?? {};
1156
+ description: "Marks the user's onboarding as complete after validating the durable approved-profile marker and a persisted active first signal created at or after that approval. " +
1157
+ "Web onboarding should pass the exact intentId returned by /intents/confirm; legacy clients may omit it and use any eligible active intent. " +
1158
+ "This preserves privacy fields, records firstSignalIntentId/currentStep, and is idempotent.",
1159
+ querySchema: z.object({
1160
+ intentId: z.string().min(1).optional().describe("Exact first-signal ID returned by the confirmation endpoint."),
1161
+ }).strict(),
1162
+ handler: async ({ context, query }) => {
1163
+ const currentUser = await userDb.getUser();
1164
+ const currentOnboarding = currentUser?.onboarding ?? context.user.onboarding ?? {};
1143
1165
  if (currentOnboarding.completedAt) {
1144
1166
  logger.verbose("Onboarding already completed, skipping", { userId: context.userId });
1145
- return success({ message: "Onboarding already completed." });
1167
+ return success({
1168
+ message: "Onboarding already completed.",
1169
+ completedAt: currentOnboarding.completedAt,
1170
+ ...(currentOnboarding.firstSignalIntentId
1171
+ ? { intentId: currentOnboarding.firstSignalIntentId }
1172
+ : {}),
1173
+ });
1146
1174
  }
1147
- const confirmedProfile = await userDb.getProfile();
1148
- if (!confirmedProfile) {
1175
+ if (!currentOnboarding.profileConfirmedAt) {
1149
1176
  return error("Onboarding cannot be completed until the user has a confirmed profile. Show the profile draft, get explicit approval, then save it before finishing onboarding.");
1150
1177
  }
1178
+ const profileConfirmedAtMs = Date.parse(currentOnboarding.profileConfirmedAt);
1179
+ if (!Number.isFinite(profileConfirmedAtMs)) {
1180
+ return error("Onboarding cannot be completed because the durable profile confirmation timestamp is invalid. Confirm the approved profile again before finishing onboarding.");
1181
+ }
1151
1182
  const activeIntents = await userDb.getActiveIntents();
1152
- if (activeIntents.length === 0) {
1153
- return error("Onboarding cannot be completed until the user has at least one active intent. Ask what they are open to right now and create the first signal before finishing onboarding.");
1183
+ const isEligibleFirstSignal = (intent) => {
1184
+ const createdAtMs = intent.createdAt.getTime();
1185
+ return Number.isFinite(createdAtMs) && createdAtMs >= profileConfirmedAtMs;
1186
+ };
1187
+ const firstSignal = query.intentId
1188
+ ? activeIntents.find((intent) => intent.id === query.intentId)
1189
+ : activeIntents.find(isEligibleFirstSignal);
1190
+ if (!firstSignal) {
1191
+ return error(query.intentId
1192
+ ? "Onboarding cannot be completed because the confirmed first signal is not active for this user."
1193
+ : "Onboarding cannot be completed until the user has at least one active intent created after profile confirmation. Ask what they are open to right now and create the first signal before finishing onboarding.");
1194
+ }
1195
+ if (!isEligibleFirstSignal(firstSignal)) {
1196
+ return error("Onboarding cannot be completed because the selected first signal was created before profile confirmation. Create and confirm a new signal before finishing onboarding.");
1154
1197
  }
1198
+ const completedAt = new Date().toISOString();
1155
1199
  await userDb.updateUser({
1156
1200
  onboarding: {
1157
1201
  ...currentOnboarding,
1158
- completedAt: new Date().toISOString(),
1202
+ firstSignalIntentId: firstSignal.id,
1203
+ currentStep: 'complete',
1204
+ completedAt,
1159
1205
  },
1160
1206
  });
1161
1207
  if (grantDefaultSystemPermissions) {
@@ -1169,8 +1215,8 @@ export function createEnrichmentTools(defineTool, deps) {
1169
1215
  });
1170
1216
  }
1171
1217
  }
1172
- logger.info("Onboarding completed", { userId: context.userId });
1173
- return success({ message: "Onboarding complete." });
1218
+ logger.info("Onboarding completed", { userId: context.userId, intentId: firstSignal.id });
1219
+ return success({ message: "Onboarding complete.", intentId: firstSignal.id, completedAt });
1174
1220
  },
1175
1221
  });
1176
1222
  return [readUserContexts, recordOnboardingPrivacyConsent, previewUserContext, confirmUserContext, createUserContext, updateUserContext, getEnrichmentRun, cancelEnrichmentRun, completeOnboarding];