@indexnetwork/protocol 3.9.0-rc.284.1 → 3.11.0-rc.286.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.
Files changed (43) hide show
  1. package/dist/intent/intent.graph.d.ts.map +1 -1
  2. package/dist/intent/intent.graph.js +16 -51
  3. package/dist/intent/intent.graph.js.map +1 -1
  4. package/dist/negotiation/negotiation.graph.d.ts.map +1 -1
  5. package/dist/negotiation/negotiation.graph.js +2 -1
  6. package/dist/negotiation/negotiation.graph.js.map +1 -1
  7. package/dist/network/network.recommender.d.ts +2 -7
  8. package/dist/network/network.recommender.d.ts.map +1 -1
  9. package/dist/network/network.recommender.js +3 -8
  10. package/dist/network/network.recommender.js.map +1 -1
  11. package/dist/network/network.tools.d.ts.map +1 -1
  12. package/dist/network/network.tools.js +7 -9
  13. package/dist/network/network.tools.js.map +1 -1
  14. package/dist/opportunity/discovery-question.helper.d.ts +2 -2
  15. package/dist/opportunity/discovery-question.helper.d.ts.map +1 -1
  16. package/dist/opportunity/discovery-question.helper.js +1 -17
  17. package/dist/opportunity/discovery-question.helper.js.map +1 -1
  18. package/dist/opportunity/opportunity.discover.d.ts.map +1 -1
  19. package/dist/opportunity/opportunity.discover.js +5 -2
  20. package/dist/opportunity/opportunity.discover.js.map +1 -1
  21. package/dist/opportunity/question.prompt.d.ts +7 -2
  22. package/dist/opportunity/question.prompt.d.ts.map +1 -1
  23. package/dist/opportunity/question.prompt.js +1 -15
  24. package/dist/opportunity/question.prompt.js.map +1 -1
  25. package/dist/profile/profile.graph.d.ts.map +1 -1
  26. package/dist/profile/profile.graph.js +22 -19
  27. package/dist/profile/profile.graph.js.map +1 -1
  28. package/dist/questioner/questioner.presets.d.ts.map +1 -1
  29. package/dist/questioner/questioner.presets.js +10 -21
  30. package/dist/questioner/questioner.presets.js.map +1 -1
  31. package/dist/questioner/questioner.types.d.ts +6 -19
  32. package/dist/questioner/questioner.types.d.ts.map +1 -1
  33. package/dist/questioner/questioner.types.js.map +1 -1
  34. package/dist/shared/agent/tool.helpers.d.ts +7 -6
  35. package/dist/shared/agent/tool.helpers.d.ts.map +1 -1
  36. package/dist/shared/agent/tool.helpers.js.map +1 -1
  37. package/dist/shared/interfaces/database.interface.d.ts +3 -3
  38. package/dist/shared/interfaces/database.interface.d.ts.map +1 -1
  39. package/dist/shared/interfaces/database.interface.js.map +1 -1
  40. package/dist/shared/schemas/discovery-question.schema.d.ts +2 -1
  41. package/dist/shared/schemas/discovery-question.schema.d.ts.map +1 -1
  42. package/dist/shared/schemas/discovery-question.schema.js.map +1 -1
  43. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"opportunity.discover.js","sourceRoot":"/","sources":["opportunity/opportunity.discover.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Run discovery from an ad-hoc query (e.g. chat \"find me a mentor\", \"who needs a React developer\").\n *\n * Invokes the opportunity graph with the query as sourceText. The HyDE graph's\n * LensInferrer automatically infers search lenses from the query, replacing the\n * old hardcoded strategy selection. Returns formatted candidates (enriched with\n * profile name/bio) for chat display.\n *\n * Used by the discover_opportunities chat tool.\n */\n\nimport type { Opportunity, ChatGraphCompositeDatabase, UserRecord } from \"../shared/interfaces/database.interface.js\";\nimport type { Cache } from \"../shared/interfaces/cache.interface.js\";\nimport type { OpportunityGraphOptions, CandidateMatch, SourceProfileData } from \"./opportunity.state.js\";\nimport type { DiscoveryNegotiation, DiscoverySummary } from \"./question.prompt.js\";\nimport type { QuestionerEnqueueFn } from \"../questioner/questioner.types.js\";\nimport { OpportunityPresenter, gatherPresenterContext, type OpportunityPresentationResult, type HomeCardPresentationResult, type HomeCardLLMResult, type HomeCardPresenterInput } from \"./opportunity.presenter.js\";\nimport { MINIMAL_MAIN_TEXT_MAX_CHARS, getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from \"./opportunity.labels.js\";\nimport { viewerCentricCardSummary, narratorRemarkFromReasoning } from \"./opportunity.presentation.js\";\nimport { protocolLogger, withCallLogging } from \"../shared/observability/protocol.logger.js\";\nimport type { ChatSummaryReader } from \"../shared/interfaces/chat-summary.interface.js\";\nimport type { ChatContextDigest } from \"../shared/schemas/chat-context.schema.js\";\nimport type { QuestionGeneratorReader } from \"../shared/interfaces/question-generator.interface.js\";\nimport type { NegotiationSummaryReader } from \"../shared/interfaces/negotiation-summary.interface.js\";\nimport type { DiscoveryNegotiationDigest } from \"../shared/schemas/negotiation-digest.schema.js\";\nimport { buildFallbackDigest } from \"../negotiation/negotiation.summarizer.js\";\nimport type { Question, QuestionStrategy } from \"../shared/schemas/question.schema.js\";\nimport { traceAgent, tracePhase } from \"../shared/observability/trace.js\";\nimport { requestContext } from \"../shared/observability/request-context.js\";\nimport { buildDiscoveryQuestionInput } from \"./discovery-question.helper.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"OpportunityDiscover\");\n\n/**\n * Per-negotiation summarizer budget. The summarizer fires one LLM call per\n * partial-or-full negotiation (concurrently via Promise.all). Without a cap\n * one slow OpenRouter route dominates the post-discovery tail and pushes the\n * whole MCP response past Railway's ~60 s no-upstream-bytes timeout. Falls\n * back to a deterministic digest when the deadline fires, so question\n * generation still has structured input.\n */\nconst NEGOTIATION_SUMMARY_TIMEOUT_MS_DEFAULT = 5_000;\n/**\n * Question-generator budget. Sized against Railway's ~60 s edge timeout:\n * the discovery + evaluation + negotiate phases consume ~50 s on the slow\n * path, leaving ~10 s of headroom for the tail. 12 s is the larger end of\n * \"fits\"; the question step usually completes in 4-8 s, so most legitimate\n * calls finish well inside. Aborted calls return `null` (no questions);\n * the rest of the discovery payload still ships.\n *\n * Documented at opportunity.tools.ts:912-921 as historically uncapped —\n * this is the cap.\n */\nconst DISCOVERY_QUESTIONS_TIMEOUT_MS_DEFAULT = 12_000;\n\n/**\n * Parse a positive integer env var, clamped to the safe-integer range so a\n * malformed env value cannot crash `AbortSignal.timeout` (which throws on\n * values outside `[0, MAX_SAFE_INTEGER]`). Mirrors the precedent in\n * `negotiation.agent.ts` (`isValidTimeoutMs`).\n */\nfunction parsePositiveIntEnv(name: string, fallback: number): number {\n const raw = process.env[name];\n if (!raw) return fallback;\n const n = Number.parseInt(raw, 10);\n if (!Number.isFinite(n) || n <= 0 || n > Number.MAX_SAFE_INTEGER) return fallback;\n return n;\n}\n\nfunction combineWithDeadline(\n callerSignal: AbortSignal | undefined,\n deadlineMs: number,\n): AbortSignal {\n const deadline = AbortSignal.timeout(deadlineMs);\n if (!callerSignal) return deadline;\n return AbortSignal.any([callerSignal, deadline]);\n}\n\n/** Compiled opportunity graph (from OpportunityGraphFactory.createGraph()). */\nexport type CompiledOpportunityGraph = ReturnType<\n import(\"./opportunity.graph.js\").OpportunityGraphFactory[\"createGraph\"]\n>;\n\nexport interface DiscoverInput {\n /** Compiled opportunity graph (already has DB, embedder, cache, HyDE graph). */\n opportunityGraph: CompiledOpportunityGraph;\n /** Database for enriching candidates with profile (getProfile). */\n database: ChatGraphCompositeDatabase;\n userId: string;\n query: string;\n indexScope: string[];\n limit?: number;\n /** Optional intent to use as discovery source and for triggeredBy (e.g. from opportunity queue). */\n triggerIntentId?: string;\n /** When set, filter discovery candidates to this specific user only (direct connection). */\n targetUserId?: string;\n /** When set, discover on behalf of this user (introducer flow). The caller (userId) becomes the introducer. */\n onBehalfOfUserId?: string;\n /** When provided, each opportunity is enriched with personalized presentation (headline, personalizedSummary, suggestedAction). */\n presenter?: OpportunityPresenter;\n /**\n * When true, use the full home card presentation format (with narratorRemark, action labels, mutualIntentsLabel).\n * This enables rendering the same rich opportunity cards in chat as on the home page.\n */\n useHomeCardFormat?: boolean;\n /**\n * When true, skip the LLM presenter and return minimal card data only (faster for chat).\n * Sets homeCardPresentation and narratorChip from static labels and match reason.\n */\n minimalForChat?: boolean;\n /** When set (e.g. from chat), create opportunities as draft with context.conversationId = chatSessionId. */\n chatSessionId?: string;\n /** Redis cache for discovery pagination. When provided, remaining candidates are cached for continuation. */\n cache?: Cache;\n /**\n * Which flow is invoking discovery. Drives the graph's trigger-aware branches\n * in persist (initial status) and negotiate (park window + streaming). When\n * omitted, the graph defaults to 'ambient'. Pass 'orchestrator' from the\n * chat `discover_opportunities` tool so users see drafts stream in and the\n * accepted-pair lookup surfaces existing connections.\n */\n trigger?: 'ambient' | 'orchestrator';\n /**\n * MCP-only. When set, the opportunity graph's negotiate phase is capped at\n * this many milliseconds; on timeout the caller gets whichever candidates\n * finished, the rest stay in `negotiating` and finalize in the background.\n * Chat, ambient queue, and all other callers omit this — existing behavior.\n */\n negotiateTimeoutMs?: number;\n /** Optional read-through chat-session digest reader. Required for chatContext enrichment. */\n chatSummary?: ChatSummaryReader;\n /**\n * Optional negotiation summarizer. When provided, each post-negotiation digest\n * replaces the raw negotiation in the decision-question generator's input,\n * keeping that prompt small and predictable regardless of candidate count.\n * When omitted, a deterministic fallback digest is built per negotiation.\n */\n negotiationSummary?: NegotiationSummaryReader;\n /** Optional decision-question generator. When omitted, no questions are produced. */\n questionGenerator?: QuestionGeneratorReader;\n /**\n * Master switch for decision-question generation. When false, this code path\n * is skipped entirely regardless of trigger. The composition root passes\n * `process.env.ENABLE_DISCOVERY_QUESTIONS === \"true\"`.\n */\n enableQuestions?: boolean;\n /**\n * Optional async question enqueue callback. When provided, question generation\n * is dispatched asynchronously to the QuestionerQueue instead of running inline\n * via the `questionGenerator`. The callback receives an enqueue payload and\n * returns a promise that resolves when the job is enqueued (not when generation\n * completes).\n */\n questionerEnqueue?: QuestionerEnqueueFn;\n}\n\n/** Context used by the minimal (no-LLM) path; only introducerName is needed for narrator chip. */\ntype MinimalPresenterContext = { introducerName?: string };\n\n/** Max chars for bio and matchReason in chat tool results to keep context manageable. */\nconst MAX_FIELD_CHARS = 100;\n\nfunction truncateForChat(\n s: string | undefined,\n max = MAX_FIELD_CHARS,\n): string | undefined {\n if (s == null || s === \"\") return undefined;\n const trimmed = s.trim();\n if (trimmed.length <= max) return trimmed;\n return trimmed.slice(0, max) + \"...\";\n}\n\n/** One formatted opportunity for chat (candidate-facing). */\nexport interface FormattedDiscoveryCandidate {\n opportunityId: string;\n userId: string;\n name?: string;\n avatar?: string | null;\n bio?: string;\n matchReason: string;\n score: number;\n status?: string;\n /** Present when DiscoverInput.presenter was provided (basic presentation). */\n presentation?: OpportunityPresentationResult;\n /** Present when DiscoverInput.useHomeCardFormat is true (full home card contract). */\n homeCardPresentation?: HomeCardPresentationResult;\n /** Viewer's role in this opportunity. */\n viewerRole?: string;\n /** Whether the viewer (as introducer) has approved the introduction. */\n viewerApproved?: boolean;\n /** Full user record for the candidate (needed for socials / Telegram fallback). */\n candidateUser?: UserRecord | null;\n /** Whether the counterpart is a ghost (not yet onboarded) user. */\n isGhost?: boolean;\n /** Narrator chip for home card display (name + remark, with optional avatar/userId for introducer). */\n narratorChip?: {\n name: string;\n text: string;\n avatar?: string | null;\n userId?: string;\n };\n /** Second party in introducer arrow layout (candidate -> secondParty). Present when viewer is introducer. */\n secondParty?: {\n name: string;\n avatar?: string | null;\n userId?: string;\n };\n}\n\n/** One step for debug visibility (subgraph/subtask). */\nexport interface DiscoverDebugStep {\n step: string;\n detail?: string;\n /** Structured data for rich display (e.g., candidate counts, scores). */\n data?: Record<string, unknown>;\n}\n\n/** One existing connection (no new opportunity created; user already has one with this person). */\nexport interface ExistingConnection {\n userId: string;\n name: string;\n status?: string;\n opportunityId?: string;\n}\n\n/** Statuses for which an existing connection may be shown as a card; others (accepted, rejected, expired) are only mentioned in text. */\nconst EXISTING_CONNECTION_CARD_STATUSES = ['draft', 'latent', 'pending'] as const;\n\nexport interface DiscoverResult {\n found: boolean;\n count: number;\n message?: string;\n opportunities?: FormattedDiscoveryCandidate[];\n /** Existing connections eligible for card display (draft, latent, or pending). Others are mention-only. */\n existingConnections?: ExistingConnection[];\n /** All existing connections for mention text (e.g. \"You already have a connection with: X (pending), Y (draft).\"). */\n existingConnectionsForMention?: ExistingConnection[];\n /**\n * Orchestrator-only: accepted opportunities the persist step found between the\n * discoverer and a candidate counterparty (status='accepted'). Populated from\n * OpportunityGraphState.dedupAlreadyAccepted. Used by the discover_opportunities\n * tool to tell the LLM \"this pair is already connected — open the existing\n * chat rather than creating a new draft\". Empty for the ambient trigger.\n */\n alreadyAcceptedPairs?: Array<{ opportunityId: string; counterpartyUserId: string }>;\n /** When true, the chat agent should call create_intent(suggestedIntentDescription) and retry discovery. */\n createIntentSuggested?: boolean;\n /** Description to pass to create_intent when createIntentSuggested is true. */\n suggestedIntentDescription?: string;\n /** Internal steps for copy-debug (select_strategies, opportunity_graph, enrich, etc.). */\n debugSteps?: DiscoverDebugStep[];\n /** Pagination metadata -- present when there are more unevaluated candidates. */\n pagination?: {\n discoveryId: string;\n evaluated: number;\n remaining: number;\n };\n /** 0–3 decision questions produced by the orchestrator path. Omitted when none. */\n questions?: Question[];\n /** Debug metadata for `debugMeta.discoveryQuestions` plumbing. */\n discoveryQuestionsDebug?: {\n inputMode: \"transcripts\" | \"insights\";\n finalCount: number;\n strategies: QuestionStrategy[];\n durationMs: number;\n };\n}\n\n/** Input for the shared enrichment helper. */\ninterface EnrichOpportunitiesInput {\n opportunities: Opportunity[];\n database: ChatGraphCompositeDatabase;\n userId: string;\n chatSessionId?: string;\n minimalForChat?: boolean;\n presenter?: OpportunityPresenter;\n useHomeCardFormat?: boolean;\n debugSteps: DiscoverDebugStep[];\n /** IDs of pre-existing opportunities merged into the list; these preserve their real status. */\n existingOpportunityIds?: Set<string>;\n /** When set, bypass the embedding filter for this specific user (direct connection mode). */\n targetUserId?: string;\n}\n\n/**\n * Enrich raw opportunities with profile data, presentation (LLM or minimal),\n * and narrator chips. Shared by both `runDiscoverFromQuery` and `continueDiscovery`\n * to avoid duplicating the profile-lookup / presenter / card-formatting logic.\n *\n * @param input - Enrichment context (opportunities, database, viewer, presentation options).\n * @returns Formatted discovery candidates ready for chat or home card display.\n */\nasync function enrichOpportunities(\n input: EnrichOpportunitiesInput,\n): Promise<FormattedDiscoveryCandidate[]> {\n const {\n opportunities,\n database,\n userId,\n chatSessionId,\n minimalForChat,\n presenter,\n useHomeCardFormat,\n debugSteps,\n existingOpportunityIds,\n targetUserId,\n } = input;\n\n const baseEnrichedRaw = await Promise.all(\n opportunities.map(async (opp) => {\n const viewerIsIntroducer = opp.actors.some((a) => a.role === 'introducer' && a.userId === userId);\n // When the viewer is the introducer, the \"candidate\" for the card is the agent\n // (the discovered person), not the patient (the intro target / onBehalfOfUserId).\n // For non-introducer views, pick the first non-viewer, non-introducer actor.\n const nonViewerNonIntroducerActors = opp.actors.filter((a) => a.userId !== userId && a.role !== 'introducer');\n const candidateActor = viewerIsIntroducer\n ? (nonViewerNonIntroducerActors.find((a) => a.role === 'agent') ?? nonViewerNonIntroducerActors[0])\n : nonViewerNonIntroducerActors[0];\n const candidateUserId = candidateActor?.userId ?? \"\";\n const viewerActor = opp.actors.find((a) => a.userId === userId);\n const [profile, candidateUser] = candidateUserId\n ? await Promise.all([database.getProfile(candidateUserId), database.getUser(candidateUserId)])\n : [null, null];\n // Skip soft-deleted users (deletedAt is set)\n if (candidateUser && 'deletedAt' in candidateUser && candidateUser.deletedAt) return null;\n const isDirectTarget = targetUserId && candidateUserId === targetUserId;\n if (!isDirectTarget && !candidateUser?.isGhost && !profile) return null;\n const confidence =\n typeof opp.interpretation?.confidence === \"number\"\n ? opp.interpretation.confidence\n : parseFloat(String(opp.interpretation?.confidence ?? 0)) || 0;\n return {\n opportunity: opp,\n candidateUserId,\n viewerRole: viewerActor?.role ?? \"party\",\n viewerApproved: viewerActor?.approved === true,\n candidateUser,\n profile,\n confidence,\n };\n }),\n );\n const baseEnriched = baseEnrichedRaw.filter((item): item is NonNullable<typeof item> => item !== null);\n debugSteps.push({\n step: \"enrich_profiles\",\n detail: `${baseEnriched.length} profile(s)`,\n });\n\n // Batch-fetch user records (candidates, introducers, and other party actors) for name/avatar fallback.\n const allActorUserIds = new Set<string>();\n for (const item of baseEnriched) {\n for (const actor of item.opportunity.actors) {\n if (actor.userId && actor.userId !== userId) {\n allActorUserIds.add(actor.userId);\n }\n }\n }\n const candidateUserIds = [...allActorUserIds];\n const [viewerUser, ...userResults] = await Promise.all([\n database.getUser(userId),\n ...candidateUserIds.map((id) => database.getUser(id)),\n ]);\n const avatarByUserId = new Map<string, string | null>();\n const nameByUserId = new Map<string, string | null>();\n const isGhostByUserId = new Map<string, boolean>();\n candidateUserIds.forEach((id, i) => {\n const user = userResults[i] ?? null;\n avatarByUserId.set(id, user?.avatar ?? null);\n nameByUserId.set(id, user?.name ?? null);\n isGhostByUserId.set(id, user?.isGhost ?? false);\n });\n const viewerName = viewerUser?.name ?? undefined;\n\n // Retry name resolution for candidates whose name is still missing.\n // The profile or user record may not have been ready on the first fetch\n // (e.g. profile generation still in flight). One retry covers transient gaps.\n const missingNameIds = baseEnriched\n .map((item) => item.candidateUserId)\n .filter((id) => id && !nameByUserId.get(id) && !baseEnriched.find((b) => b.candidateUserId === id && b.profile?.identity?.name));\n if (missingNameIds.length > 0) {\n const retried = await Promise.all(\n missingNameIds.map(async (id) => {\n const [profile, user] = await Promise.all([\n database.getProfile(id),\n database.getUser(id),\n ]);\n return { id, profile, user };\n }),\n );\n for (const r of retried) {\n const name = r.profile?.identity?.name ?? r.user?.name ?? null;\n if (name) nameByUserId.set(r.id, name);\n // Also update the baseEnriched profile so counterpartName picks it up\n if (r.profile) {\n const item = baseEnriched.find((b) => b.candidateUserId === r.id);\n if (item && !item.profile) item.profile = r.profile;\n }\n if (r.user?.avatar && !avatarByUserId.get(r.id)) {\n avatarByUserId.set(r.id, r.user.avatar);\n }\n }\n logger.verbose(\"[enrichOpportunities] Retried name lookup for candidates with missing names\", {\n attempted: missingNameIds.length,\n resolved: retried.filter((r) => r.profile?.identity?.name ?? r.user?.name).length,\n });\n }\n\n let presentations: OpportunityPresentationResult[] | undefined;\n let homeCardPresentations: HomeCardPresentationResult[] | undefined;\n let presenterContexts:\n | (Awaited<ReturnType<typeof gatherPresenterContext>> | MinimalPresenterContext)[]\n | undefined;\n\n if (minimalForChat && baseEnriched.length > 0) {\n // Minimal path: no LLM, viewer-centric card text (introduce counterpart to viewer)\n const counterpartName = (n: {\n profile?: { identity?: { name?: string } } | null;\n candidateUserId: string;\n }) => n.profile?.identity?.name ?? nameByUserId.get(n.candidateUserId) ?? \"\";\n homeCardPresentations = baseEnriched.map((item) => {\n const name = counterpartName(item)?.trim();\n const reasoning = item.opportunity.interpretation?.reasoning ?? \"\";\n const introducerName = item.opportunity.detection?.createdByName ?? undefined;\n const viewerIsIntroducer = item.opportunity.actors.some(\n (a) => a.role === \"introducer\" && a.userId === userId,\n );\n\n // For introducer view, find the second party (target user) name\n let secondPartyName: string | undefined;\n if (viewerIsIntroducer) {\n const otherPartyActors = item.opportunity.actors.filter(\n (a) => a.role !== \"introducer\" && a.userId !== item.candidateUserId,\n );\n if (otherPartyActors.length > 0) {\n const otherUserId = otherPartyActors[0].userId;\n secondPartyName = nameByUserId.get(otherUserId) ?? undefined;\n }\n }\n\n const isCounterpartGhost = isGhostByUserId.get(item.candidateUserId) ?? false;\n const personalizedSummary = viewerCentricCardSummary(\n reasoning,\n name,\n MINIMAL_MAIN_TEXT_MAX_CHARS,\n viewerName,\n introducerName,\n );\n return {\n headline: viewerIsIntroducer && secondPartyName\n ? `${name} → ${secondPartyName}`\n : (name ? `Connection with ${name}` : \"Suggested connection\"),\n personalizedSummary,\n digestSummary: name\n ? `You might like meeting ${name} based on your current interests.`\n : \"This connection may be relevant to your current interests.\",\n suggestedAction: \"Start a conversation to connect.\",\n narratorRemark: narratorRemarkFromReasoning(reasoning, name, viewerName),\n primaryActionLabel: getPrimaryActionLabel(viewerIsIntroducer ? \"introducer\" : \"party\"),\n secondaryActionLabel: SECONDARY_ACTION_LABEL,\n mutualIntentsLabel: \"Suggested connection\",\n greeting: \"\",\n };\n });\n presenterContexts = baseEnriched.map((item) => ({\n introducerName: item.opportunity.detection.createdByName ?? undefined,\n })) as MinimalPresenterContext[];\n } else if (presenter && baseEnriched.length > 0) {\n try {\n presenterContexts = await Promise.all(\n baseEnriched.map(({ opportunity }) =>\n gatherPresenterContext(database, opportunity, userId),\n ),\n );\n\n if (useHomeCardFormat) {\n // Use full home card format with action labels, narrator remark, etc.\n const fullContexts = presenterContexts as Awaited<\n ReturnType<typeof gatherPresenterContext>\n >[];\n const homeCardInputs: HomeCardPresenterInput[] = fullContexts.map(\n (ctx, idx) => ({\n ...ctx,\n mutualIntentCount: undefined,\n opportunityStatus: baseEnriched[idx].opportunity.status,\n }),\n );\n const llmResults = await presenter.presentHomeCardBatch(\n homeCardInputs,\n { concurrency: 5 },\n );\n // Append hardcoded button labels to LLM results\n homeCardPresentations = llmResults.map((llm, idx) => ({\n ...llm,\n primaryActionLabel: getPrimaryActionLabel(baseEnriched[idx].viewerRole),\n secondaryActionLabel: SECONDARY_ACTION_LABEL,\n }));\n } else {\n // Use basic presentation format\n presentations = await presenter.presentBatch(\n presenterContexts as Awaited<\n ReturnType<typeof gatherPresenterContext>\n >[],\n {\n concurrency: 5,\n },\n );\n }\n } catch (error) {\n logger.warn(\n \"Presenter enrichment failed during opportunity discovery; returning base results without presentations\",\n {\n userId,\n opportunitiesCount: baseEnriched.length,\n useHomeCardFormat,\n error: error instanceof Error ? error.message : String(error),\n },\n );\n presentations = undefined;\n homeCardPresentations = undefined;\n }\n }\n\n const enriched: FormattedDiscoveryCandidate[] = baseEnriched.map(\n (item, idx) => {\n const homeCard = homeCardPresentations?.[idx];\n const ctx = presenterContexts?.[idx];\n\n // Build narrator chip for home card format\n let narratorChip: FormattedDiscoveryCandidate[\"narratorChip\"];\n if (homeCard) {\n const viewerIsIntroducer = item.opportunity.actors.some(\n (a) => a.role === \"introducer\" && a.userId === userId,\n );\n if (viewerIsIntroducer) {\n narratorChip = {\n name: \"You\",\n text: homeCard.narratorRemark,\n userId: userId,\n };\n } else {\n const introducerActor = item.opportunity.actors.find(\n (a) => a.role === \"introducer\" && a.userId !== userId,\n );\n if (introducerActor) {\n const introducerName =\n ctx?.introducerName ??\n nameByUserId.get(introducerActor.userId) ??\n \"Someone\";\n narratorChip = {\n name: introducerName,\n text: homeCard.narratorRemark,\n userId: introducerActor.userId,\n avatar: avatarByUserId.get(introducerActor.userId) ?? null,\n };\n } else {\n narratorChip = {\n name: \"Index\",\n text: homeCard.narratorRemark,\n };\n }\n }\n }\n\n const isGhost = isGhostByUserId.get(item.candidateUserId) ?? false;\n\n // Build secondParty for introducer view (the other non-introducer party)\n let secondParty: FormattedDiscoveryCandidate[\"secondParty\"];\n const viewerIsIntroducerForCard = item.opportunity.actors.some(\n (a) => a.role === \"introducer\" && a.userId === userId,\n );\n if (viewerIsIntroducerForCard) {\n const otherPartyActor = item.opportunity.actors.find(\n (a) => a.role !== \"introducer\" && a.userId !== item.candidateUserId,\n );\n if (otherPartyActor) {\n const otherName = nameByUserId.get(otherPartyActor.userId) ?? undefined;\n if (otherName) {\n secondParty = {\n name: otherName,\n avatar: avatarByUserId.get(otherPartyActor.userId) ?? null,\n userId: otherPartyActor.userId,\n };\n }\n }\n }\n\n return {\n opportunityId: item.opportunity.id,\n userId: item.candidateUserId,\n name: item.profile?.identity?.name ?? nameByUserId.get(item.candidateUserId) ?? undefined,\n avatar: avatarByUserId.get(item.candidateUserId) ?? null,\n bio: truncateForChat(item.profile?.identity?.bio),\n matchReason:\n truncateForChat(\n item.opportunity.interpretation?.reasoning ?? \"\",\n ) ?? \"\",\n score: item.confidence,\n status: chatSessionId && !existingOpportunityIds?.has(item.opportunity.id) ? \"draft\" : item.opportunity.status,\n viewerRole: item.viewerRole,\n viewerApproved: item.viewerApproved,\n candidateUser: item.candidateUser,\n isGhost,\n ...(presentations?.[idx] && { presentation: presentations[idx] }),\n ...(homeCard && {\n homeCardPresentation: homeCard,\n }),\n ...(narratorChip && { narratorChip }),\n ...(secondParty && { secondParty }),\n };\n },\n );\n debugSteps.push({\n step: \"format_cards\",\n detail: `${enriched.length} card(s)`,\n });\n\n return enriched;\n}\n\n/** Cached discovery session data stored in Redis. */\ninterface CachedDiscoverySession {\n candidates: CandidateMatch[];\n userId: string;\n onBehalfOfUserId?: string;\n query: string;\n indexScope: string[];\n options: OpportunityGraphOptions;\n /**\n * Carried across pagination so page 2+ stays on the same flow as page 1.\n * Without this, orchestrator runs would fall back to the 'ambient' default\n * mid-search and lose the shorter park window + accepted-pair dedup.\n */\n trigger?: 'ambient' | 'orchestrator';\n}\n\n/**\n * Run discovery from an ad-hoc query (e.g. \"find me a mentor\", \"who needs a React developer\").\n * The HyDE graph's LensInferrer automatically infers search lenses from the query.\n * Invokes the opportunity graph and returns formatted candidates suitable for chat display.\n */\nexport async function runDiscoverFromQuery(\n input: DiscoverInput,\n): Promise<DiscoverResult> {\n const {\n opportunityGraph,\n database,\n userId,\n query,\n indexScope,\n limit = 5,\n triggerIntentId,\n targetUserId,\n onBehalfOfUserId,\n chatSessionId,\n trigger,\n negotiateTimeoutMs,\n } = input;\n\n if (indexScope.length === 0) {\n return {\n found: false,\n count: 0,\n message:\n \"You need to join at least one network (community) to discover opportunities. Use read_networks to see available networks, or create one.\",\n };\n }\n\n const debugSteps: DiscoverDebugStep[] = [];\n\n // When query is empty, the opportunity graph uses the user's intents in scope (indexedIntents[0].payload)\n // Lens inference is handled automatically by the HyDE graph's LensInferrer\n const queryOrEmpty = query?.trim() ?? \"\";\n // Orchestrator discovery defers the initial status to the graph's\n // trigger-aware `resolveInitialStatus`, which opens at 'negotiating' so\n // the accepted-draft streaming flow can run. Ambient chat discovery still\n // wants the legacy 'draft' status so the chat-only lifecycle holds; other\n // ambient callers keep 'latent'.\n const isOrchestrator = trigger === 'orchestrator';\n const options: OpportunityGraphOptions = {\n limit,\n ...(!isOrchestrator && { initialStatus: chatSessionId ? \"draft\" : \"latent\" }),\n ...(chatSessionId ? { conversationId: chatSessionId } : {}),\n ...(negotiateTimeoutMs !== undefined && { negotiateTimeoutMs }),\n };\n\n return withCallLogging(\n logger,\n \"runDiscoverFromQuery\",\n {\n userId,\n queryPreview: queryOrEmpty\n ? queryOrEmpty.substring(0, 50)\n : \"(using user intents in scope)\",\n indexScopeCount: indexScope.length,\n limit,\n },\n async () => {\n const result = await invokeWithAbortSignal(opportunityGraph, {\n userId,\n searchQuery: queryOrEmpty || undefined,\n // A single index resolves to the strict networkId override (membership-\n // validated in the scope node). Multiple indexes (e.g. a network-scoped\n // agent's bound network + personal index) pass through as indexScope so\n // the graph stays bounded instead of falling back to all networks.\n networkId: indexScope.length === 1 ? indexScope[0] : undefined,\n ...(indexScope.length > 1 ? { indexScope } : {}),\n triggerIntentId,\n targetUserId,\n onBehalfOfUserId,\n options,\n ...(trigger && { trigger }),\n });\n\n // Extract trace from graph and append to debugSteps\n const graphTrace = Array.isArray(result.trace) ? result.trace : [];\n for (const t of graphTrace) {\n debugSteps.push({\n step: t.node,\n detail: t.detail,\n ...(t.data ? { data: t.data } : {}),\n });\n }\n\n // Bail early if the graph returned an error\n if (result.error) {\n logger.warn(\"runDiscoverFromQuery graph returned error\", { error: result.error });\n return {\n found: false,\n count: 0,\n message: \"Failed to find opportunities. Please try again.\",\n debugSteps,\n };\n }\n\n // Cache remaining candidates for pagination\n let pagination: DiscoverResult['pagination'] | undefined;\n const remainingCandidates: CandidateMatch[] = result.remainingCandidates || [];\n if (remainingCandidates.length > 0 && input.cache) {\n try {\n const discoveryId = crypto.randomUUID();\n const cacheKey = `discovery:${userId}:${discoveryId}`;\n await input.cache.set(cacheKey, {\n candidates: remainingCandidates,\n userId,\n onBehalfOfUserId,\n query: queryOrEmpty,\n indexScope,\n options,\n ...(trigger && { trigger }),\n } satisfies CachedDiscoverySession, { ttl: 1800 }); // 30 minutes\n pagination = {\n discoveryId,\n evaluated: (result.candidates?.length ?? 0) - remainingCandidates.length,\n remaining: remainingCandidates.length,\n };\n } catch (cacheErr) {\n logger.warn(\"Failed to cache discovery pagination\", {\n userId,\n error: cacheErr instanceof Error ? cacheErr.message : String(cacheErr),\n });\n }\n }\n\n // Refine phase: a sibling of the opportunity graph in the trace tree.\n // Holds the three post-discovery summarization steps. Each step is its\n // own traced agent so it appears as a leaf in the trace UI.\n //\n // Negotiation summary: compress each raw negotiation into a fixed-size\n // structured digest so the question generator's prompt stays small\n // (a 10-candidate turn used to balloon past 60 KB and stall upstream).\n // Decision questions: generate up to 3 clarifying questions from the\n // digests + chat context.\n const { questionPayload } = await tracePhase(\"Refine\", async () => {\n const negotiationDigests = await summarizeNegotiations({\n negotiations: result.discoveryNegotiations ?? [],\n summarizer: input.negotiationSummary,\n enableQuestions: input.enableQuestions ?? false,\n trigger,\n });\n const questionPayload = await maybeBuildQuestions({\n trigger,\n enableQuestions: input.enableQuestions ?? false,\n chatSummary: input.chatSummary,\n questionGenerator: input.questionGenerator,\n chatSessionId,\n graphResult: result,\n negotiationDigests,\n query: queryOrEmpty,\n questionerEnqueue: input.questionerEnqueue,\n userId: input.userId,\n });\n return { negotiationDigests, questionPayload };\n });\n\n if (result.createIntentSuggested && result.suggestedIntentDescription) {\n if (chatSessionId) {\n return {\n found: false,\n count: 0,\n message: \"No matching opportunities found. Try a different query.\",\n pagination,\n ...(questionPayload.questions !== undefined ? { questions: questionPayload.questions } : {}),\n ...(questionPayload.debug !== undefined ? { discoveryQuestionsDebug: questionPayload.debug } : {}),\n };\n }\n return {\n found: false,\n count: 0,\n createIntentSuggested: true,\n suggestedIntentDescription: result.suggestedIntentDescription,\n message:\n \"No matching opportunities; add an intent with the suggested description to improve discovery.\",\n debugSteps,\n pagination,\n ...(questionPayload.questions !== undefined ? { questions: questionPayload.questions } : {}),\n ...(questionPayload.debug !== undefined ? { discoveryQuestionsDebug: questionPayload.debug } : {}),\n };\n }\n\n let opportunities: Opportunity[] = Array.isArray(result.opportunities)\n ? result.opportunities\n : [];\n let existingOpportunityIds: Set<string> | undefined;\n const rawExistingBetweenActors = Array.isArray(result.existingBetweenActors)\n ? result.existingBetweenActors\n : [];\n // Orchestrator trigger populates this; ambient returns []. Kept as a\n // loosely-typed pass-through because DiscoverResult is consumed by\n // callers (chat tool, tests) that already model the narrower shape.\n const alreadyAcceptedPairs = Array.isArray(\n (result as { dedupAlreadyAccepted?: Array<{ opportunityId: string; counterpartyUserId: string }> })\n .dedupAlreadyAccepted,\n )\n ? (result as { dedupAlreadyAccepted: Array<{ opportunityId: string; counterpartyUserId: string }> })\n .dedupAlreadyAccepted\n : [];\n // Enrich existing-between-actors with names so the tool can say \"You already have a connection with X (pending).\"\n const existingConnections: ExistingConnection[] = await Promise.all(\n rawExistingBetweenActors.map(async (item) => {\n const user = await database.getUser(item.candidateUserId);\n return {\n userId: item.candidateUserId,\n name: user?.name ?? \"Someone\",\n ...(item.existingStatus ? { status: item.existingStatus } : {}),\n ...(item.existingOpportunityId ? { opportunityId: item.existingOpportunityId } : {}),\n };\n }),\n );\n if (existingConnections.length > 0) {\n logger.verbose(\"[runDiscoverFromQuery] Skipped duplicates; existing connections\", {\n count: existingConnections.length,\n userIds: existingConnections.map((c) => c.userId),\n });\n }\n // Only expose existing connections as cards when status is in EXISTING_CONNECTION_CARD_STATUSES (draft, latent, pending); others are mention-only.\n const existingConnectionsForCards = existingConnections.filter((c) =>\n c.status != null && EXISTING_CONNECTION_CARD_STATUSES.includes(c.status as typeof EXISTING_CONNECTION_CARD_STATUSES[number])\n );\n\n // Fetch full opportunity data for existing connections that should be shown as cards\n // and merge them with the newly created opportunities\n if (existingConnectionsForCards.length > 0) {\n const existingOpps = await Promise.all(\n existingConnectionsForCards\n .filter((c) => c.opportunityId)\n .map((c) => database.getOpportunity(c.opportunityId!))\n );\n const validExistingOpps = existingOpps.filter((o): o is Opportunity => o != null);\n if (validExistingOpps.length > 0) {\n logger.verbose(\"[runDiscoverFromQuery] Including existing opportunities as cards\", {\n count: validExistingOpps.length,\n ids: validExistingOpps.map((o) => o.id),\n });\n existingOpportunityIds = new Set(validExistingOpps.map((o) => o.id));\n opportunities = [...opportunities, ...validExistingOpps];\n }\n }\n\n // Chat discovery: when we have chatSessionId we just invoked the graph; all result.opportunities\n // were created in this call and belong to this session. Do not filter by status: the enricher\n // may set status to pending/latent when merging with related opportunities, so filtering to\n // \"draft\" would incorrectly drop them.\n if (chatSessionId && (result.opportunities?.length ?? 0) > 0) {\n logger.verbose(\"[runDiscoverFromQuery] Chat session opportunities from graph\", {\n count: opportunities.length,\n statuses: opportunities.map((o) => o.status),\n });\n }\n debugSteps.push({\n step: \"opportunity_graph\",\n detail: `${opportunities.length} opportunity(ies)${existingConnections.length > 0 ? `, ${existingConnections.length} existing` : \"\"}`,\n });\n\n if (opportunities.length === 0) {\n if (existingConnections.length > 0) {\n return {\n found: true,\n count: 0,\n message:\n \"No new opportunities created; you already have a connection with: \" +\n existingConnections.map((c) => `${c.name}${c.status ? ` (${c.status})` : \"\"}`).join(\", \") +\n \". View on your home page.\",\n existingConnections: existingConnectionsForCards,\n existingConnectionsForMention: existingConnections,\n ...(alreadyAcceptedPairs.length > 0 && { alreadyAcceptedPairs }),\n debugSteps,\n pagination,\n ...(questionPayload.questions !== undefined ? { questions: questionPayload.questions } : {}),\n ...(questionPayload.debug !== undefined ? { discoveryQuestionsDebug: questionPayload.debug } : {}),\n };\n }\n return {\n found: false,\n count: 0,\n message:\n \"No matching opportunities found. Try a different query or create intents to improve matching.\",\n ...(alreadyAcceptedPairs.length > 0 && { alreadyAcceptedPairs }),\n debugSteps,\n pagination,\n ...(questionPayload.questions !== undefined ? { questions: questionPayload.questions } : {}),\n ...(questionPayload.debug !== undefined ? { discoveryQuestionsDebug: questionPayload.debug } : {}),\n };\n }\n\n const enriched = await enrichOpportunities({\n opportunities,\n database,\n userId,\n chatSessionId,\n minimalForChat: input.minimalForChat,\n presenter: input.presenter,\n useHomeCardFormat: input.useHomeCardFormat,\n debugSteps,\n existingOpportunityIds,\n targetUserId,\n });\n\n return {\n found: true,\n count: enriched.length,\n opportunities: enriched,\n ...(existingConnectionsForCards.length > 0 ? { existingConnections: existingConnectionsForCards } : {}),\n ...(existingConnections.length > 0 ? { existingConnectionsForMention: existingConnections } : {}),\n ...(alreadyAcceptedPairs.length > 0 ? { alreadyAcceptedPairs } : {}),\n debugSteps,\n pagination,\n ...(questionPayload.questions !== undefined ? { questions: questionPayload.questions } : {}),\n ...(questionPayload.debug !== undefined ? { discoveryQuestionsDebug: questionPayload.debug } : {}),\n };\n },\n { context: { userId }, logOutput: false },\n ).catch((err) => {\n return {\n found: false,\n count: 0,\n message: \"Failed to find opportunities. Please try again.\",\n };\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// DECISION-QUESTION HELPER\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype GraphResultLike = {\n sourceProfile?: SourceProfileData | null;\n discoveryNegotiations?: DiscoveryNegotiation[];\n discoverySummary?: DiscoverySummary | null;\n};\n\ninterface MaybeBuildQuestionsInput {\n trigger: 'ambient' | 'orchestrator' | undefined;\n enableQuestions: boolean;\n chatSummary: ChatSummaryReader | undefined;\n questionGenerator: QuestionGeneratorReader | undefined;\n chatSessionId: string | undefined;\n graphResult: GraphResultLike;\n /** Pre-built per-negotiation digests. Pass [] when summarization is unavailable or disabled. */\n negotiationDigests: DiscoveryNegotiationDigest[];\n query: string;\n /** Optional async enqueue callback for background question generation. */\n questionerEnqueue?: DiscoverInput['questionerEnqueue'];\n /** User ID needed for the enqueue payload. */\n userId?: string;\n}\n\n/**\n * Run the negotiation summarizer over every negotiation in this discovery turn.\n * Each summarization is independent — run them concurrently via Promise.all.\n * When the summarizer is missing (no LLM available) or fails for an individual\n * negotiation, fall back to a deterministic digest so the downstream generator\n * still has structured input.\n */\nasync function summarizeNegotiations(args: {\n negotiations: DiscoveryNegotiation[];\n summarizer: NegotiationSummaryReader | undefined;\n enableQuestions: boolean;\n trigger: 'ambient' | 'orchestrator' | undefined;\n}): Promise<DiscoveryNegotiationDigest[]> {\n // Skip the LLM round-trip entirely when questions won't be built.\n if (!args.enableQuestions || args.trigger !== 'orchestrator') return [];\n if (args.negotiations.length === 0) return [];\n\n const perNegTimeoutMs = parsePositiveIntEnv(\n \"NEGOTIATION_SUMMARY_TIMEOUT_MS\",\n NEGOTIATION_SUMMARY_TIMEOUT_MS_DEFAULT,\n );\n const callerSignal = requestContext.getStore()?.abortSignal;\n\n return traceAgent(\n `Negotiation summary (${args.negotiations.length})`,\n () =>\n Promise.all(\n args.negotiations.map(async (n) => {\n if (!args.summarizer) return buildFallbackDigest(n);\n // Per-negotiation deadline: one slow OpenRouter route used to\n // dominate the post-discovery tail. With a cap, an aborted\n // summarizer falls back to a deterministic digest so the\n // question generator still has structured input.\n const signal = combineWithDeadline(callerSignal, perNegTimeoutMs);\n try {\n const d = await args.summarizer.summarize(n, { signal });\n return d ?? buildFallbackDigest(n);\n } catch (err) {\n // Attribute cause from err.name (AbortError), not from\n // signal.aborted — the latter is read post-catch and can race a\n // deadline-trip-after-unrelated-error, producing a misleading log.\n const aborted = err instanceof Error && err.name === \"AbortError\";\n logger.warn(\"negotiationSummary.summarize threw — using fallback digest\", {\n counterpartyHint: n.counterpartyHint,\n aborted,\n error: err instanceof Error ? err.message : String(err),\n });\n return buildFallbackDigest(n);\n }\n }),\n ),\n (digests) => `${digests.length} digest${digests.length === 1 ? \"\" : \"s\"}`,\n );\n}\n\nasync function maybeBuildQuestions(args: MaybeBuildQuestionsInput): Promise<{\n questions?: Question[];\n debug?: DiscoverResult[\"discoveryQuestionsDebug\"];\n}> {\n if (!args.enableQuestions) return {};\n if (args.trigger !== 'orchestrator') return {};\n\n // Hardcoded — `insights` mode is planned for a later slice. Warn if the env\n // var is set so operators aren't surprised when reporting still says\n // \"transcripts\".\n if (process.env.DISCOVERY_QUESTIONS_INPUT_MODE === \"insights\") {\n logger.warn(\"DISCOVERY_QUESTIONS_INPUT_MODE=insights is not yet implemented; falling back to transcripts\");\n }\n const inputMode: \"transcripts\" | \"insights\" = \"transcripts\";\n\n let chatContext: ChatContextDigest | undefined;\n if (args.chatSummary && args.chatSessionId) {\n const sessionId = args.chatSessionId;\n const summary = args.chatSummary;\n chatContext = await traceAgent(\n \"Chat summary\",\n async () => {\n try {\n return (await summary.getDigest(sessionId)) ?? undefined;\n } catch (err) {\n logger.warn(\"chatSummary.getDigest threw — proceeding without digest\", {\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n return undefined;\n }\n },\n (digest) => (digest ? \"loaded\" : \"empty\"),\n );\n }\n\n // ── Async enqueue path ──────────────────────────────────────────────────\n // When questionerEnqueue is provided, dispatch question generation\n // asynchronously to the background QuestionerQueue. This replaces the\n // inline generator path. Questions will be persisted to DB by the queue\n // worker and served via GET /api/questions.\n if (args.questionerEnqueue && args.userId) {\n const summary = args.graphResult.discoverySummary ?? {\n totalCandidates: 0,\n opportunitiesFound: 0,\n noOpportunityCount: 0,\n timeoutCount: 0,\n roleDistribution: {},\n };\n\n const enqueueInput = buildDiscoveryQuestionInput({\n query: args.query,\n sourceProfile: args.graphResult.sourceProfile ?? null,\n negotiationDigests: args.negotiationDigests,\n summary,\n chatContext,\n now: new Date().toISOString(),\n });\n\n try {\n await args.questionerEnqueue({\n mode: 'discovery',\n userId: args.userId,\n sourceType: 'discovery',\n sourceId: args.chatSessionId ?? crypto.randomUUID(),\n context: enqueueInput,\n conversationId: args.chatSessionId,\n });\n logger.info(\"Question generation enqueued to QuestionerQueue\", {\n userId: args.userId,\n trigger: args.trigger,\n });\n } catch (err) {\n logger.warn(\"Failed to enqueue question generation\", {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n return {};\n }\n\n // ── Inline generator path (backward compat) ────────────────────────────\n if (!args.questionGenerator) return {};\n\n const negotiationDigests = args.negotiationDigests;\n const summary = args.graphResult.discoverySummary ?? {\n totalCandidates: 0,\n opportunitiesFound: 0,\n noOpportunityCount: 0,\n timeoutCount: 0,\n roleDistribution: {},\n };\n\n const input = buildDiscoveryQuestionInput({\n query: args.query,\n sourceProfile: args.graphResult.sourceProfile ?? null,\n negotiationDigests,\n summary,\n chatContext,\n now: new Date().toISOString(),\n });\n\n const questionGenerator = args.questionGenerator;\n const generatorStart = Date.now();\n const questionsTimeoutMs = parsePositiveIntEnv(\n \"DISCOVERY_QUESTIONS_TIMEOUT_MS\",\n DISCOVERY_QUESTIONS_TIMEOUT_MS_DEFAULT,\n );\n const questionsSignal = combineWithDeadline(\n requestContext.getStore()?.abortSignal,\n questionsTimeoutMs,\n );\n const genResult = await traceAgent(\n \"Decision questions\",\n async () => {\n try {\n return await questionGenerator.generate(input, { signal: questionsSignal });\n } catch (err) {\n logger.warn(\"questionGenerator.generate threw — suppressing questions\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n },\n (r) => {\n const count = r?.questions?.length ?? 0;\n return `${count} question${count === 1 ? \"\" : \"s\"}`;\n },\n );\n const durationMs = Date.now() - generatorStart;\n\n const finalCount = genResult?.questions?.length ?? 0;\n const strategies: QuestionStrategy[] = genResult?.strategies ?? [];\n\n return {\n ...(genResult && genResult.questions.length > 0 ? { questions: genResult.questions } : {}),\n debug: {\n inputMode,\n finalCount,\n strategies,\n durationMs,\n },\n };\n}\n\n/**\n * Continue a paginated discovery by evaluating the next batch of cached candidates.\n * Loads candidates from Redis, invokes the opportunity graph in continue_discovery mode,\n * then enriches and returns the results with updated pagination metadata.\n *\n * @param input - Continuation context (graph, database, cache, discoveryId, etc.).\n * @returns Discovery result with enriched opportunities and pagination state.\n */\nexport async function continueDiscovery(input: {\n opportunityGraph: CompiledOpportunityGraph;\n database: ChatGraphCompositeDatabase;\n cache: Cache;\n userId: string;\n discoveryId: string;\n /** If provided, validates the cached session's indexScope contains this index. */\n expectedIndexId?: string;\n limit?: number;\n chatSessionId?: string;\n minimalForChat?: boolean;\n presenter?: OpportunityPresenter;\n useHomeCardFormat?: boolean;\n}): Promise<DiscoverResult> {\n const {\n opportunityGraph,\n database,\n cache,\n userId,\n discoveryId,\n expectedIndexId,\n limit = 20,\n chatSessionId,\n } = input;\n const cacheKey = `discovery:${userId}:${discoveryId}`;\n\n const cached = await cache.get<CachedDiscoverySession>(cacheKey);\n\n if (!cached) {\n return {\n found: false,\n count: 0,\n message: \"Discovery session expired or not found. Please start a new search.\",\n };\n }\n\n // Validate that the cached session's scope matches the current chat context\n if (expectedIndexId && !cached.indexScope.includes(expectedIndexId)) {\n return {\n found: false,\n count: 0,\n message: \"Discovery session was created in a different context. Please start a new search.\",\n };\n }\n\n const debugSteps: DiscoverDebugStep[] = [];\n\n const result = await invokeWithAbortSignal(opportunityGraph, {\n userId,\n searchQuery: cached.query || undefined,\n candidates: cached.candidates,\n operationMode: 'continue_discovery' as const,\n onBehalfOfUserId: cached.onBehalfOfUserId,\n // Carry the original trigger so page 2+ stays on the same flow as page\n // 1 (orchestrator negotiations with 60s park window + accepted-pair\n // dedup, or ambient with 5-min park window).\n ...(cached.trigger && { trigger: cached.trigger }),\n options: {\n ...cached.options,\n limit,\n ...(chatSessionId ? { conversationId: chatSessionId } : {}),\n },\n });\n\n // Extract trace from graph and append to debugSteps\n const graphTrace = result.trace || [];\n for (const t of graphTrace) {\n debugSteps.push({\n step: t.node,\n detail: t.detail,\n ...(t.data ? { data: t.data } : {}),\n });\n }\n\n // Bail early if the graph returned an error\n if (result.error) {\n logger.warn(\"continueDiscovery graph returned error\", { error: result.error });\n return {\n found: false,\n count: 0,\n message: \"Discovery continuation failed. Please start a new search.\",\n debugSteps,\n };\n }\n\n // Update cache with remaining candidates or delete if exhausted\n const remaining: CandidateMatch[] = result.remainingCandidates || [];\n let pagination: DiscoverResult['pagination'] | undefined;\n try {\n if (remaining.length > 0) {\n await cache.set(cacheKey, {\n ...cached,\n candidates: remaining,\n } satisfies CachedDiscoverySession, { ttl: 1800 });\n pagination = {\n discoveryId,\n evaluated: cached.candidates.length - remaining.length,\n remaining: remaining.length,\n };\n } else {\n await cache.delete(cacheKey);\n }\n } catch (cacheErr) {\n logger.warn(\"Failed to update discovery pagination cache\", {\n userId,\n discoveryId,\n error: cacheErr instanceof Error ? cacheErr.message : String(cacheErr),\n });\n }\n\n // Check for opportunities in result\n const opportunities: Opportunity[] = Array.isArray(result.opportunities) ? result.opportunities : [];\n\n if (opportunities.length === 0) {\n return {\n found: false,\n count: 0,\n message: \"No more matching opportunities found in the remaining candidates.\",\n debugSteps,\n pagination,\n };\n }\n\n const enriched = await enrichOpportunities({\n opportunities,\n database,\n userId,\n chatSessionId,\n minimalForChat: input.minimalForChat,\n presenter: input.presenter,\n useHomeCardFormat: input.useHomeCardFormat,\n debugSteps,\n });\n\n return {\n found: true,\n count: enriched.length,\n opportunities: enriched,\n debugSteps,\n pagination,\n };\n}\n"]}
1
+ {"version":3,"file":"opportunity.discover.js","sourceRoot":"/","sources":["opportunity/opportunity.discover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,EAAwB,sBAAsB,EAA4H,MAAM,4BAA4B,CAAC;AACpN,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACrH,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACtG,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAM7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAE/E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAC5E,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAExE,MAAM,MAAM,GAAG,cAAc,CAAC,qBAAqB,CAAC,CAAC;AAErD;;;;;;;GAOG;AACH,MAAM,sCAAsC,GAAG,IAAK,CAAC;AACrD;;;;;;;;;;GAUG;AACH,MAAM,sCAAsC,GAAG,KAAM,CAAC;AAEtD;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,IAAY,EAAE,QAAgB;IACzD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,GAAG;QAAE,OAAO,QAAQ,CAAC;IAC1B,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,gBAAgB;QAAE,OAAO,QAAQ,CAAC;IAClF,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,mBAAmB,CAC1B,YAAqC,EACrC,UAAkB;IAElB,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,YAAY;QAAE,OAAO,QAAQ,CAAC;IACnC,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AACnD,CAAC;AAmFD,yFAAyF;AACzF,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,SAAS,eAAe,CACtB,CAAqB,EACrB,GAAG,GAAG,eAAe;IAErB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACzB,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,OAAO,CAAC;IAC1C,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC;AACvC,CAAC;AAuDD,yIAAyI;AACzI,MAAM,iCAAiC,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAU,CAAC;AA0DlF;;;;;;;GAOG;AACH,KAAK,UAAU,mBAAmB,CAChC,KAA+B;IAE/B,MAAM,EACJ,aAAa,EACb,QAAQ,EACR,MAAM,EACN,aAAa,EACb,cAAc,EACd,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,sBAAsB,EACtB,YAAY,GACb,GAAG,KAAK,CAAC;IAEV,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,GAAG,CACvC,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC9B,MAAM,kBAAkB,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QAClG,+EAA+E;QAC/E,kFAAkF;QAClF,6EAA6E;QAC7E,MAAM,4BAA4B,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;QAC9G,MAAM,cAAc,GAAG,kBAAkB;YACvC,CAAC,CAAC,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,4BAA4B,CAAC,CAAC,CAAC,CAAC;YACnG,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,eAAe,GAAG,cAAc,EAAE,MAAM,IAAI,EAAE,CAAC;QACrD,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QAChE,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,GAAG,eAAe;YAC9C,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;YAC9F,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjB,6CAA6C;QAC7C,IAAI,aAAa,IAAI,WAAW,IAAI,aAAa,IAAI,aAAa,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QAC1F,MAAM,cAAc,GAAG,YAAY,IAAI,eAAe,KAAK,YAAY,CAAC;QACxE,IAAI,CAAC,cAAc,IAAI,CAAC,aAAa,EAAE,OAAO,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QACxE,MAAM,UAAU,GACd,OAAO,GAAG,CAAC,cAAc,EAAE,UAAU,KAAK,QAAQ;YAChD,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,UAAU;YAC/B,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,UAAU,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnE,OAAO;YACL,WAAW,EAAE,GAAG;YAChB,eAAe;YACf,UAAU,EAAE,WAAW,EAAE,IAAI,IAAI,OAAO;YACxC,cAAc,EAAE,WAAW,EAAE,QAAQ,KAAK,IAAI;YAC9C,aAAa;YACb,OAAO;YACP,UAAU;SACX,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IACF,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,EAAoC,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACvG,UAAU,CAAC,IAAI,CAAC;QACd,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,aAAa;KAC5C,CAAC,CAAC;IAEH,uGAAuG;IACvG,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;YAC5C,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC5C,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,gBAAgB,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC;IAC9C,MAAM,CAAC,UAAU,EAAE,GAAG,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACrD,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;QACxB,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;KACtD,CAAC,CAAC;IACH,MAAM,cAAc,GAAG,IAAI,GAAG,EAAyB,CAAC;IACxD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAyB,CAAC;IACtD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAmB,CAAC;IACnD,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;QACpC,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC;QAC7C,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC;QACzC,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,IAAI,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,UAAU,EAAE,IAAI,IAAI,SAAS,CAAC;IAEjD,oEAAoE;IACpE,wEAAwE;IACxE,8EAA8E;IAC9E,MAAM,cAAc,GAAG,YAAY;SAChC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC;SACnC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IACnI,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YAC9B,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;aACrB,CAAC,CAAC;YACH,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC/B,CAAC,CAAC,CACH,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC;YAC/D,IAAI,IAAI;gBAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACvC,sEAAsE;YACtE,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;gBAClE,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO;oBAAE,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;YACtD,CAAC;YACD,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBAChD,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QACD,MAAM,CAAC,OAAO,CAAC,6EAA6E,EAAE;YAC5F,SAAS,EAAE,cAAc,CAAC,MAAM;YAChC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,MAAM;SAClF,CAAC,CAAC;IACL,CAAC;IAED,IAAI,aAA0D,CAAC;IAC/D,IAAI,qBAA+D,CAAC;IACpE,IAAI,iBAES,CAAC;IAEd,IAAI,cAAc,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,mFAAmF;QACnF,MAAM,eAAe,GAAG,CAAC,CAGxB,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;QAC7E,qBAAqB,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAChD,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;YAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,SAAS,IAAI,EAAE,CAAC;YACnE,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,aAAa,IAAI,SAAS,CAAC;YAC9E,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CACrD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CACtD,CAAC;YAEF,gEAAgE;YAChE,IAAI,eAAmC,CAAC;YACxC,IAAI,kBAAkB,EAAE,CAAC;gBACvB,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CACrD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,eAAe,CACpE,CAAC;gBACF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAChC,MAAM,WAAW,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;oBAC/C,eAAe,GAAG,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,SAAS,CAAC;gBAC/D,CAAC;YACH,CAAC;YAED,MAAM,kBAAkB,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,KAAK,CAAC;YAC9E,MAAM,mBAAmB,GAAG,wBAAwB,CAClD,SAAS,EACT,IAAI,EACJ,2BAA2B,EAC3B,UAAU,EACV,cAAc,CACf,CAAC;YACF,OAAO;gBACL,QAAQ,EAAE,kBAAkB,IAAI,eAAe;oBAC7C,CAAC,CAAC,GAAG,IAAI,MAAM,eAAe,EAAE;oBAChC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC;gBAC/D,mBAAmB;gBACnB,aAAa,EAAE,IAAI;oBACjB,CAAC,CAAC,0BAA0B,IAAI,mCAAmC;oBACnE,CAAC,CAAC,4DAA4D;gBAChE,eAAe,EAAE,kCAAkC;gBACnD,cAAc,EAAE,2BAA2B,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC;gBACxE,kBAAkB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC;gBACtF,oBAAoB,EAAE,sBAAsB;gBAC5C,kBAAkB,EAAE,sBAAsB;gBAC1C,QAAQ,EAAE,EAAE;aACb,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,iBAAiB,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC9C,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,aAAa,IAAI,SAAS;SACtE,CAAC,CAA8B,CAAC;IACnC,CAAC;SAAM,IAAI,SAAS,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,IAAI,CAAC;YACH,iBAAiB,GAAG,MAAM,OAAO,CAAC,GAAG,CACnC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CACnC,sBAAsB,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,CACtD,CACF,CAAC;YAEF,IAAI,iBAAiB,EAAE,CAAC;gBACtB,sEAAsE;gBACtE,MAAM,YAAY,GAAG,iBAElB,CAAC;gBACJ,MAAM,cAAc,GAA6B,YAAY,CAAC,GAAG,CAC/D,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;oBACb,GAAG,GAAG;oBACN,iBAAiB,EAAE,SAAS;oBAC5B,iBAAiB,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,MAAM;iBACxD,CAAC,CACH,CAAC;gBACF,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,oBAAoB,CACrD,cAAc,EACd,EAAE,WAAW,EAAE,CAAC,EAAE,CACnB,CAAC;gBACF,gDAAgD;gBAChD,qBAAqB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;oBACpD,GAAG,GAAG;oBACN,kBAAkB,EAAE,qBAAqB,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC;oBACvE,oBAAoB,EAAE,sBAAsB;iBAC7C,CAAC,CAAC,CAAC;YACN,CAAC;iBAAM,CAAC;gBACN,gCAAgC;gBAChC,aAAa,GAAG,MAAM,SAAS,CAAC,YAAY,CAC1C,iBAEG,EACH;oBACE,WAAW,EAAE,CAAC;iBACf,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CACT,wGAAwG,EACxG;gBACE,MAAM;gBACN,kBAAkB,EAAE,YAAY,CAAC,MAAM;gBACvC,iBAAiB;gBACjB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC9D,CACF,CAAC;YACF,aAAa,GAAG,SAAS,CAAC;YAC1B,qBAAqB,GAAG,SAAS,CAAC;QACpC,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAkC,YAAY,CAAC,GAAG,CAC9D,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC,GAAG,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC,GAAG,CAAC,CAAC;QAErC,2CAA2C;QAC3C,IAAI,YAAyD,CAAC;QAC9D,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CACrD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CACtD,CAAC;YACF,IAAI,kBAAkB,EAAE,CAAC;gBACvB,YAAY,GAAG;oBACb,IAAI,EAAE,KAAK;oBACX,IAAI,EAAE,QAAQ,CAAC,cAAc;oBAC7B,MAAM,EAAE,MAAM;iBACf,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAClD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CACtD,CAAC;gBACF,IAAI,eAAe,EAAE,CAAC;oBACpB,MAAM,cAAc,GAClB,GAAG,EAAE,cAAc;wBACnB,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC;wBACxC,SAAS,CAAC;oBACZ,YAAY,GAAG;wBACb,IAAI,EAAE,cAAc;wBACpB,IAAI,EAAE,QAAQ,CAAC,cAAc;wBAC7B,MAAM,EAAE,eAAe,CAAC,MAAM;wBAC9B,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,IAAI;qBAC3D,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACN,YAAY,GAAG;wBACb,IAAI,EAAE,OAAO;wBACb,IAAI,EAAE,QAAQ,CAAC,cAAc;qBAC9B,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,KAAK,CAAC;QAEnE,yEAAyE;QACzE,IAAI,WAAuD,CAAC;QAC5D,MAAM,yBAAyB,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAC5D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CACtD,CAAC;QACF,IAAI,yBAAyB,EAAE,CAAC;YAC9B,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAClD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,eAAe,CACpE,CAAC;YACF,IAAI,eAAe,EAAE,CAAC;gBACpB,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;gBACxE,IAAI,SAAS,EAAE,CAAC;oBACd,WAAW,GAAG;wBACZ,IAAI,EAAE,SAAS;wBACf,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,IAAI;wBAC1D,MAAM,EAAE,eAAe,CAAC,MAAM;qBAC/B,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO;YACL,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE;YAClC,MAAM,EAAE,IAAI,CAAC,eAAe;YAC5B,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,SAAS;YACzF,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,IAAI;YACxD,GAAG,EAAE,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC;YACjD,WAAW,EACT,eAAe,CACb,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,SAAS,IAAI,EAAE,CACjD,IAAI,EAAE;YACT,KAAK,EAAE,IAAI,CAAC,UAAU;YACtB,MAAM,EAAE,aAAa,IAAI,CAAC,sBAAsB,EAAE,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM;YAC9G,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,OAAO;YACP,GAAG,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YACjE,GAAG,CAAC,QAAQ,IAAI;gBACd,oBAAoB,EAAE,QAAQ;aAC/B,CAAC;YACF,GAAG,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,CAAC;YACrC,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;SACpC,CAAC;IACJ,CAAC,CACF,CAAC;IACF,UAAU,CAAC,IAAI,CAAC;QACd,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,UAAU;KACrC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAkBD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAoB;IAEpB,MAAM,EACJ,gBAAgB,EAChB,QAAQ,EACR,MAAM,EACN,KAAK,EACL,UAAU,EACV,KAAK,GAAG,CAAC,EACT,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,OAAO,EACP,kBAAkB,GACnB,GAAG,KAAK,CAAC;IAEV,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,CAAC;YACR,OAAO,EACL,0IAA0I;SAC7I,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAwB,EAAE,CAAC;IAE3C,0GAA0G;IAC1G,2EAA2E;IAC3E,MAAM,YAAY,GAAG,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACzC,kEAAkE;IAClE,wEAAwE;IACxE,0EAA0E;IAC1E,0EAA0E;IAC1E,iCAAiC;IACjC,MAAM,cAAc,GAAG,OAAO,KAAK,cAAc,CAAC;IAClD,MAAM,OAAO,GAA4B;QACvC,KAAK;QACL,GAAG,CAAC,CAAC,cAAc,IAAI,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC7E,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,kBAAkB,KAAK,SAAS,IAAI,EAAE,kBAAkB,EAAE,CAAC;KAChE,CAAC;IAEF,OAAO,eAAe,CACpB,MAAM,EACN,sBAAsB,EACtB;QACE,MAAM;QACN,YAAY,EAAE,YAAY;YACxB,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC;YAC/B,CAAC,CAAC,+BAA+B;QACnC,eAAe,EAAE,UAAU,CAAC,MAAM;QAClC,KAAK;KACN,EACD,KAAK,IAAI,EAAE;QACT,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,gBAAgB,EAAE;YAC3D,MAAM;YACN,WAAW,EAAE,YAAY,IAAI,SAAS;YACtC,wEAAwE;YACxE,wEAAwE;YACxE,wEAAwE;YACxE,mEAAmE;YACnE,SAAS,EAAE,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;YAC9D,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChD,eAAe;YACf,YAAY;YACZ,gBAAgB;YAChB,OAAO;YACP,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;SAC5B,CAAC,CAAC;QAEH,oDAAoD;QACpD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,UAAU,CAAC,IAAI,CAAC;gBACd,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACpC,CAAC,CAAC;QACL,CAAC;QAED,4CAA4C;QAC5C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,2CAA2C,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YAClF,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,iDAAiD;gBAC1D,UAAU;aACX,CAAC;QACJ,CAAC;QAED,4CAA4C;QAC5C,IAAI,UAAoD,CAAC;QACzD,MAAM,mBAAmB,GAAqB,MAAM,CAAC,mBAAmB,IAAI,EAAE,CAAC;QAC/E,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAClD,IAAI,CAAC;gBACH,MAAM,WAAW,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;gBACxC,MAAM,QAAQ,GAAG,aAAa,MAAM,IAAI,WAAW,EAAE,CAAC;gBACtD,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;oBAC9B,UAAU,EAAE,mBAAmB;oBAC/B,MAAM;oBACN,gBAAgB;oBAChB,KAAK,EAAE,YAAY;oBACnB,UAAU;oBACV,OAAO;oBACP,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;iBACK,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,aAAa;gBACjE,UAAU,GAAG;oBACX,WAAW;oBACX,SAAS,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,mBAAmB,CAAC,MAAM;oBACxE,SAAS,EAAE,mBAAmB,CAAC,MAAM;iBACtC,CAAC;YACJ,CAAC;YAAC,OAAO,QAAQ,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,CAAC,sCAAsC,EAAE;oBAClD,MAAM;oBACN,KAAK,EAAE,QAAQ,YAAY,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;iBACvE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,sEAAsE;QACtE,uEAAuE;QACvE,4DAA4D;QAC5D,EAAE;QACF,uEAAuE;QACvE,mEAAmE;QACnE,uEAAuE;QACvE,qEAAqE;QACrE,0BAA0B;QAC1B,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YAChE,MAAM,kBAAkB,GAAG,MAAM,qBAAqB,CAAC;gBACrD,YAAY,EAAE,MAAM,CAAC,qBAAqB,IAAI,EAAE;gBAChD,UAAU,EAAE,KAAK,CAAC,kBAAkB;gBACpC,eAAe,EAAE,KAAK,CAAC,eAAe,IAAI,KAAK;gBAC/C,OAAO;aACR,CAAC,CAAC;YACH,MAAM,eAAe,GAAG,MAAM,mBAAmB,CAAC;gBAChD,OAAO;gBACP,eAAe,EAAE,KAAK,CAAC,eAAe,IAAI,KAAK;gBAC/C,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;gBAC1C,aAAa;gBACb,WAAW,EAAE,MAAM;gBACnB,kBAAkB;gBAClB,KAAK,EAAE,YAAY;gBACnB,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;gBAC1C,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,WAAW,EAAE,KAAK,CAAC,MAAM;oBACvB,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;oBACzE,CAAC,CAAC,EAAE;aACP,CAAC,CAAC;YACH,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,qBAAqB,IAAI,MAAM,CAAC,0BAA0B,EAAE,CAAC;YACtE,IAAI,aAAa,EAAE,CAAC;gBAClB,OAAO;oBACL,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE,CAAC;oBACR,OAAO,EAAE,yDAAyD;oBAClE,UAAU;oBACV,GAAG,CAAC,eAAe,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC5F,GAAG,CAAC,eAAe,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACnG,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,CAAC;gBACR,qBAAqB,EAAE,IAAI;gBAC3B,0BAA0B,EAAE,MAAM,CAAC,0BAA0B;gBAC7D,OAAO,EACL,+FAA+F;gBACjG,UAAU;gBACV,UAAU;gBACV,GAAG,CAAC,eAAe,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5F,GAAG,CAAC,eAAe,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACnG,CAAC;QACJ,CAAC;QAED,IAAI,aAAa,GAAkB,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC;YACpE,CAAC,CAAC,MAAM,CAAC,aAAa;YACtB,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,sBAA+C,CAAC;QACpD,MAAM,wBAAwB,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAAC;YAC1E,CAAC,CAAC,MAAM,CAAC,qBAAqB;YAC9B,CAAC,CAAC,EAAE,CAAC;QACP,qEAAqE;QACrE,mEAAmE;QACnE,oEAAoE;QACpE,MAAM,oBAAoB,GAAG,KAAK,CAAC,OAAO,CACvC,MAAkG;aAChG,oBAAoB,CACxB;YACC,CAAC,CAAE,MAAiG;iBAC/F,oBAAoB;YACzB,CAAC,CAAC,EAAE,CAAC;QACP,kHAAkH;QAClH,MAAM,mBAAmB,GAAyB,MAAM,OAAO,CAAC,GAAG,CACjE,wBAAwB,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YAC1C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAC1D,OAAO;gBACL,MAAM,EAAE,IAAI,CAAC,eAAe;gBAC5B,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,SAAS;gBAC7B,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/D,GAAG,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrF,CAAC;QACJ,CAAC,CAAC,CACH,CAAC;QACF,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,OAAO,CAAC,iEAAiE,EAAE;gBAChF,KAAK,EAAE,mBAAmB,CAAC,MAAM;gBACjC,OAAO,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;aAClD,CAAC,CAAC;QACL,CAAC;QACD,mJAAmJ;QACnJ,MAAM,2BAA2B,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACnE,CAAC,CAAC,MAAM,IAAI,IAAI,IAAI,iCAAiC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAA0D,CAAC,CAC7H,CAAC;QAEF,qFAAqF;QACrF,sDAAsD;QACtD,IAAI,2BAA2B,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,GAAG,CACpC,2BAA2B;iBACxB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;iBAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,aAAc,CAAC,CAAC,CACzD,CAAC;YACF,MAAM,iBAAiB,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAoB,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;YAClF,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjC,MAAM,CAAC,OAAO,CAAC,kEAAkE,EAAE;oBACjF,KAAK,EAAE,iBAAiB,CAAC,MAAM;oBAC/B,GAAG,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACxC,CAAC,CAAC;gBACH,sBAAsB,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACrE,aAAa,GAAG,CAAC,GAAG,aAAa,EAAE,GAAG,iBAAiB,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QAED,iGAAiG;QACjG,8FAA8F;QAC9F,4FAA4F;QAC5F,uCAAuC;QACvC,IAAI,aAAa,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7D,MAAM,CAAC,OAAO,CAAC,8DAA8D,EAAE;gBAC7E,KAAK,EAAE,aAAa,CAAC,MAAM;gBAC3B,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;aAC7C,CAAC,CAAC;QACL,CAAC;QACD,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,mBAAmB;YACzB,MAAM,EAAE,GAAG,aAAa,CAAC,MAAM,oBAAoB,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,mBAAmB,CAAC,MAAM,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE;SACtI,CAAC,CAAC;QAEH,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnC,OAAO;oBACL,KAAK,EAAE,IAAI;oBACX,KAAK,EAAE,CAAC;oBACR,OAAO,EACL,oEAAoE;wBACpE,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;wBACzF,2BAA2B;oBAC7B,mBAAmB,EAAE,2BAA2B;oBAChD,6BAA6B,EAAE,mBAAmB;oBAClD,GAAG,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,oBAAoB,EAAE,CAAC;oBAChE,UAAU;oBACV,UAAU;oBACV,GAAG,CAAC,eAAe,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC5F,GAAG,CAAC,eAAe,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACnG,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EACL,+FAA+F;gBACjG,GAAG,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,oBAAoB,EAAE,CAAC;gBAChE,UAAU;gBACV,UAAU;gBACV,GAAG,CAAC,eAAe,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5F,GAAG,CAAC,eAAe,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACnG,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC;YACzC,aAAa;YACb,QAAQ;YACR,MAAM;YACN,aAAa;YACb,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;YAC1C,UAAU;YACV,sBAAsB;YACtB,YAAY;SACb,CAAC,CAAC;QAEH,OAAO;YACL,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,QAAQ,CAAC,MAAM;YACtB,aAAa,EAAE,QAAQ;YACvB,GAAG,CAAC,2BAA2B,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvG,GAAG,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,6BAA6B,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjG,GAAG,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,UAAU;YACV,UAAU;YACV,GAAG,CAAC,eAAe,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,eAAe,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5F,GAAG,CAAC,eAAe,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACnG,CAAC;IACJ,CAAC,EACD,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAC1C,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACd,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,CAAC;YACR,OAAO,EAAE,iDAAiD;SAC3D,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AA8BD;;;;;;GAMG;AACH,KAAK,UAAU,qBAAqB,CAAC,IAKpC;IACC,kEAAkE;IAClE,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,KAAK,cAAc;QAAE,OAAO,EAAE,CAAC;IACxE,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE9C,MAAM,eAAe,GAAG,mBAAmB,CACzC,gCAAgC,EAChC,sCAAsC,CACvC,CAAC;IACF,MAAM,YAAY,GAAG,cAAc,CAAC,QAAQ,EAAE,EAAE,WAAW,CAAC;IAE5D,OAAO,UAAU,CACf,wBAAwB,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,EACnD,GAAG,EAAE,CACH,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAChC,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACpD,8DAA8D;QAC9D,2DAA2D;QAC3D,yDAAyD;QACzD,iDAAiD;QACjD,MAAM,MAAM,GAAG,mBAAmB,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;QAClE,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YACzD,OAAO,CAAC,IAAI,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,uDAAuD;YACvD,gEAAgE;YAChE,mEAAmE;YACnE,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC;YAClE,MAAM,CAAC,IAAI,CAAC,4DAA4D,EAAE;gBACxE,gBAAgB,EAAE,CAAC,CAAC,gBAAgB;gBACpC,OAAO;gBACP,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;YACH,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CAAC,CACH,EACH,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,UAAU,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAC1E,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,IAA8B;IAI/D,IAAI,CAAC,IAAI,CAAC,eAAe;QAAE,OAAO,EAAE,CAAC;IACrC,IAAI,IAAI,CAAC,OAAO,KAAK,cAAc;QAAE,OAAO,EAAE,CAAC;IAE/C,4EAA4E;IAC5E,qEAAqE;IACrE,iBAAiB;IACjB,IAAI,OAAO,CAAC,GAAG,CAAC,8BAA8B,KAAK,UAAU,EAAE,CAAC;QAC9D,MAAM,CAAC,IAAI,CAAC,6FAA6F,CAAC,CAAC;IAC7G,CAAC;IACD,MAAM,SAAS,GAA+B,aAAa,CAAC;IAE5D,IAAI,WAA0C,CAAC;IAC/C,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC;QACjC,WAAW,GAAG,MAAM,UAAU,CAC5B,cAAc,EACd,KAAK,IAAI,EAAE;YACT,IAAI,CAAC;gBACH,OAAO,CAAC,MAAM,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC;YAC3D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC,yDAAyD,EAAE;oBACrE,SAAS;oBACT,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;iBACxD,CAAC,CAAC;gBACH,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC,EACD,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAC1C,CAAC;IACJ,CAAC;IAED,2EAA2E;IAC3E,mEAAmE;IACnE,sEAAsE;IACtE,wEAAwE;IACxE,4CAA4C;IAC5C,IAAI,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,gBAAgB,IAAI;YACnD,eAAe,EAAE,CAAC;YAClB,kBAAkB,EAAE,CAAC;YACrB,kBAAkB,EAAE,CAAC;YACrB,YAAY,EAAE,CAAC;YACf,gBAAgB,EAAE,EAAE;SACrB,CAAC;QAEF,MAAM,YAAY,GAAG,2BAA2B,CAAC;YAC/C,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;YACnC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;YAC3C,OAAO;YACP,WAAW;YACX,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SAC9B,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,iBAAiB,CAAC;gBAC3B,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,UAAU,EAAE,WAAW;gBACvB,QAAQ,EAAE,IAAI,CAAC,aAAa,IAAI,MAAM,CAAC,UAAU,EAAE;gBACnD,OAAO,EAAE,YAAY;gBACrB,cAAc,EAAE,IAAI,CAAC,aAAa;aACnC,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,iDAAiD,EAAE;gBAC7D,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,OAAO,EAAE,IAAI,CAAC,OAAO;aACtB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,uCAAuC,EAAE;gBACnD,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,0EAA0E;IAC1E,IAAI,CAAC,IAAI,CAAC,iBAAiB;QAAE,OAAO,EAAE,CAAC;IAEvC,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,CAAC;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,gBAAgB,IAAI;QACnD,eAAe,EAAE,CAAC;QAClB,kBAAkB,EAAE,CAAC;QACrB,kBAAkB,EAAE,CAAC;QACrB,YAAY,EAAE,CAAC;QACf,gBAAgB,EAAE,EAAE;KACrB,CAAC;IAEF,MAAM,KAAK,GAAG,2BAA2B,CAAC;QACxC,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;QACnC,kBAAkB;QAClB,OAAO;QACP,WAAW;QACX,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KAC9B,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,CAAC;IACjD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAClC,MAAM,kBAAkB,GAAG,mBAAmB,CAC5C,gCAAgC,EAChC,sCAAsC,CACvC,CAAC;IACF,MAAM,eAAe,GAAG,mBAAmB,CACzC,cAAc,CAAC,QAAQ,EAAE,EAAE,WAAW,EACtC,kBAAkB,CACnB,CAAC;IACF,MAAM,SAAS,GAAG,MAAM,UAAU,CAChC,oBAAoB,EACpB,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,OAAO,MAAM,iBAAiB,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,0DAA0D,EAAE;gBACtE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,EACD,CAAC,CAAC,EAAE,EAAE;QACJ,MAAM,KAAK,GAAG,CAAC,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC,CAAC;QACxC,OAAO,GAAG,KAAK,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACtD,CAAC,CACF,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC;IAE/C,MAAM,UAAU,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC,CAAC;IACrD,MAAM,UAAU,GAAuB,SAAS,EAAE,UAAU,IAAI,EAAE,CAAC;IAEnE,OAAO;QACL,GAAG,CAAC,SAAS,IAAI,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1F,KAAK,EAAE;YACL,SAAS;YACT,UAAU;YACV,UAAU;YACV,UAAU;SACX;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAavC;IACC,MAAM,EACJ,gBAAgB,EAChB,QAAQ,EACR,KAAK,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,KAAK,GAAG,EAAE,EACV,aAAa,GACd,GAAG,KAAK,CAAC;IACV,MAAM,QAAQ,GAAG,aAAa,MAAM,IAAI,WAAW,EAAE,CAAC;IAEtD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAyB,QAAQ,CAAC,CAAC;IAEjE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,CAAC;YACR,OAAO,EAAE,oEAAoE;SAC9E,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,IAAI,eAAe,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;QACpE,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,CAAC;YACR,OAAO,EAAE,kFAAkF;SAC5F,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAwB,EAAE,CAAC;IAE3C,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,gBAAgB,EAAE;QAC3D,MAAM;QACN,WAAW,EAAE,MAAM,CAAC,KAAK,IAAI,SAAS;QACtC,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,aAAa,EAAE,oBAA6B;QAC5C,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;QACzC,uEAAuE;QACvE,oEAAoE;QACpE,6CAA6C;QAC7C,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QAClD,OAAO,EAAE;YACP,GAAG,MAAM,CAAC,OAAO;YACjB,KAAK;YACL,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5D;KACF,CAAC,CAAC;IAEH,oDAAoD;IACpD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAED,4CAA4C;IAC5C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,CAAC,IAAI,CAAC,wCAAwC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAC/E,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,CAAC;YACR,OAAO,EAAE,2DAA2D;YACpE,UAAU;SACX,CAAC;IACJ,CAAC;IAED,gEAAgE;IAChE,MAAM,SAAS,GAAqB,MAAM,CAAC,mBAAmB,IAAI,EAAE,CAAC;IACrE,IAAI,UAAoD,CAAC;IACzD,IAAI,CAAC;QACH,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;gBACxB,GAAG,MAAM;gBACT,UAAU,EAAE,SAAS;aACW,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,UAAU,GAAG;gBACX,WAAW;gBACX,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM;gBACtD,SAAS,EAAE,SAAS,CAAC,MAAM;aAC5B,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAAC,OAAO,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,6CAA6C,EAAE;YACzD,MAAM;YACN,WAAW;YACX,KAAK,EAAE,QAAQ,YAAY,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;SACvE,CAAC,CAAC;IACL,CAAC;IAED,oCAAoC;IACpC,MAAM,aAAa,GAAkB,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAErG,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,CAAC;YACR,OAAO,EAAE,mEAAmE;YAC5E,UAAU;YACV,UAAU;SACX,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC;QACzC,aAAa;QACb,QAAQ;QACR,MAAM;QACN,aAAa;QACb,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,UAAU;KACX,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,QAAQ,CAAC,MAAM;QACtB,aAAa,EAAE,QAAQ;QACvB,UAAU;QACV,UAAU;KACX,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Run discovery from an ad-hoc query (e.g. chat \"find me a mentor\", \"who needs a React developer\").\n *\n * Invokes the opportunity graph with the query as sourceText. The HyDE graph's\n * LensInferrer automatically infers search lenses from the query, replacing the\n * old hardcoded strategy selection. Returns formatted candidates (enriched with\n * profile name/bio) for chat display.\n *\n * Used by the discover_opportunities chat tool.\n */\n\nimport type { Opportunity, ChatGraphCompositeDatabase, UserRecord } from \"../shared/interfaces/database.interface.js\";\nimport type { Cache } from \"../shared/interfaces/cache.interface.js\";\nimport type { OpportunityGraphOptions, CandidateMatch, SourceProfileData } from \"./opportunity.state.js\";\nimport type { DiscoveryNegotiation, DiscoverySummary } from \"./question.prompt.js\";\nimport type { QuestionerEnqueueFn } from \"../questioner/questioner.types.js\";\nimport { OpportunityPresenter, gatherPresenterContext, type OpportunityPresentationResult, type HomeCardPresentationResult, type HomeCardLLMResult, type HomeCardPresenterInput } from \"./opportunity.presenter.js\";\nimport { MINIMAL_MAIN_TEXT_MAX_CHARS, getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from \"./opportunity.labels.js\";\nimport { viewerCentricCardSummary, narratorRemarkFromReasoning } from \"./opportunity.presentation.js\";\nimport { protocolLogger, withCallLogging } from \"../shared/observability/protocol.logger.js\";\nimport type { ChatSummaryReader } from \"../shared/interfaces/chat-summary.interface.js\";\nimport type { ChatContextDigest } from \"../shared/schemas/chat-context.schema.js\";\nimport type { QuestionGeneratorReader } from \"../shared/interfaces/question-generator.interface.js\";\nimport type { NegotiationSummaryReader } from \"../shared/interfaces/negotiation-summary.interface.js\";\nimport type { DiscoveryNegotiationDigest } from \"../shared/schemas/negotiation-digest.schema.js\";\nimport { buildFallbackDigest } from \"../negotiation/negotiation.summarizer.js\";\nimport type { Question, QuestionStrategy } from \"../shared/schemas/question.schema.js\";\nimport { traceAgent, tracePhase } from \"../shared/observability/trace.js\";\nimport { requestContext } from \"../shared/observability/request-context.js\";\nimport { buildDiscoveryQuestionInput } from \"./discovery-question.helper.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"OpportunityDiscover\");\n\n/**\n * Per-negotiation summarizer budget. The summarizer fires one LLM call per\n * partial-or-full negotiation (concurrently via Promise.all). Without a cap\n * one slow OpenRouter route dominates the post-discovery tail and pushes the\n * whole MCP response past Railway's ~60 s no-upstream-bytes timeout. Falls\n * back to a deterministic digest when the deadline fires, so question\n * generation still has structured input.\n */\nconst NEGOTIATION_SUMMARY_TIMEOUT_MS_DEFAULT = 5_000;\n/**\n * Question-generator budget. Sized against Railway's ~60 s edge timeout:\n * the discovery + evaluation + negotiate phases consume ~50 s on the slow\n * path, leaving ~10 s of headroom for the tail. 12 s is the larger end of\n * \"fits\"; the question step usually completes in 4-8 s, so most legitimate\n * calls finish well inside. Aborted calls return `null` (no questions);\n * the rest of the discovery payload still ships.\n *\n * Documented at opportunity.tools.ts:912-921 as historically uncapped —\n * this is the cap.\n */\nconst DISCOVERY_QUESTIONS_TIMEOUT_MS_DEFAULT = 12_000;\n\n/**\n * Parse a positive integer env var, clamped to the safe-integer range so a\n * malformed env value cannot crash `AbortSignal.timeout` (which throws on\n * values outside `[0, MAX_SAFE_INTEGER]`). Mirrors the precedent in\n * `negotiation.agent.ts` (`isValidTimeoutMs`).\n */\nfunction parsePositiveIntEnv(name: string, fallback: number): number {\n const raw = process.env[name];\n if (!raw) return fallback;\n const n = Number.parseInt(raw, 10);\n if (!Number.isFinite(n) || n <= 0 || n > Number.MAX_SAFE_INTEGER) return fallback;\n return n;\n}\n\nfunction combineWithDeadline(\n callerSignal: AbortSignal | undefined,\n deadlineMs: number,\n): AbortSignal {\n const deadline = AbortSignal.timeout(deadlineMs);\n if (!callerSignal) return deadline;\n return AbortSignal.any([callerSignal, deadline]);\n}\n\n/** Compiled opportunity graph (from OpportunityGraphFactory.createGraph()). */\nexport type CompiledOpportunityGraph = ReturnType<\n import(\"./opportunity.graph.js\").OpportunityGraphFactory[\"createGraph\"]\n>;\n\nexport interface DiscoverInput {\n /** Compiled opportunity graph (already has DB, embedder, cache, HyDE graph). */\n opportunityGraph: CompiledOpportunityGraph;\n /** Database for enriching candidates with profile (getProfile). */\n database: ChatGraphCompositeDatabase;\n userId: string;\n query: string;\n indexScope: string[];\n limit?: number;\n /** Optional intent to use as discovery source and for triggeredBy (e.g. from opportunity queue). */\n triggerIntentId?: string;\n /** When set, filter discovery candidates to this specific user only (direct connection). */\n targetUserId?: string;\n /** When set, discover on behalf of this user (introducer flow). The caller (userId) becomes the introducer. */\n onBehalfOfUserId?: string;\n /** When provided, each opportunity is enriched with personalized presentation (headline, personalizedSummary, suggestedAction). */\n presenter?: OpportunityPresenter;\n /**\n * When true, use the full home card presentation format (with narratorRemark, action labels, mutualIntentsLabel).\n * This enables rendering the same rich opportunity cards in chat as on the home page.\n */\n useHomeCardFormat?: boolean;\n /**\n * When true, skip the LLM presenter and return minimal card data only (faster for chat).\n * Sets homeCardPresentation and narratorChip from static labels and match reason.\n */\n minimalForChat?: boolean;\n /** When set (e.g. from chat), create opportunities as draft with context.conversationId = chatSessionId. */\n chatSessionId?: string;\n /** Redis cache for discovery pagination. When provided, remaining candidates are cached for continuation. */\n cache?: Cache;\n /**\n * Which flow is invoking discovery. Drives the graph's trigger-aware branches\n * in persist (initial status) and negotiate (park window + streaming). When\n * omitted, the graph defaults to 'ambient'. Pass 'orchestrator' from the\n * chat `discover_opportunities` tool so users see drafts stream in and the\n * accepted-pair lookup surfaces existing connections.\n */\n trigger?: 'ambient' | 'orchestrator';\n /**\n * MCP-only. When set, the opportunity graph's negotiate phase is capped at\n * this many milliseconds; on timeout the caller gets whichever candidates\n * finished, the rest stay in `negotiating` and finalize in the background.\n * Chat, ambient queue, and all other callers omit this — existing behavior.\n */\n negotiateTimeoutMs?: number;\n /** Optional read-through chat-session digest reader. Required for chatContext enrichment. */\n chatSummary?: ChatSummaryReader;\n /**\n * Optional negotiation summarizer. When provided, each post-negotiation digest\n * replaces the raw negotiation in the decision-question generator's input,\n * keeping that prompt small and predictable regardless of candidate count.\n * When omitted, a deterministic fallback digest is built per negotiation.\n */\n negotiationSummary?: NegotiationSummaryReader;\n /** Optional decision-question generator. When omitted, no questions are produced. */\n questionGenerator?: QuestionGeneratorReader;\n /**\n * Master switch for decision-question generation. When false, this code path\n * is skipped entirely regardless of trigger. The composition root passes\n * `process.env.ENABLE_DISCOVERY_QUESTIONS === \"true\"`.\n */\n enableQuestions?: boolean;\n /**\n * Optional async question enqueue callback. When provided, question generation\n * is dispatched asynchronously to the QuestionerQueue instead of running inline\n * via the `questionGenerator`. The callback receives an enqueue payload and\n * returns a promise that resolves when the job is enqueued (not when generation\n * completes).\n */\n questionerEnqueue?: QuestionerEnqueueFn;\n}\n\n/** Context used by the minimal (no-LLM) path; only introducerName is needed for narrator chip. */\ntype MinimalPresenterContext = { introducerName?: string };\n\n/** Max chars for bio and matchReason in chat tool results to keep context manageable. */\nconst MAX_FIELD_CHARS = 100;\n\nfunction truncateForChat(\n s: string | undefined,\n max = MAX_FIELD_CHARS,\n): string | undefined {\n if (s == null || s === \"\") return undefined;\n const trimmed = s.trim();\n if (trimmed.length <= max) return trimmed;\n return trimmed.slice(0, max) + \"...\";\n}\n\n/** One formatted opportunity for chat (candidate-facing). */\nexport interface FormattedDiscoveryCandidate {\n opportunityId: string;\n userId: string;\n name?: string;\n avatar?: string | null;\n bio?: string;\n matchReason: string;\n score: number;\n status?: string;\n /** Present when DiscoverInput.presenter was provided (basic presentation). */\n presentation?: OpportunityPresentationResult;\n /** Present when DiscoverInput.useHomeCardFormat is true (full home card contract). */\n homeCardPresentation?: HomeCardPresentationResult;\n /** Viewer's role in this opportunity. */\n viewerRole?: string;\n /** Whether the viewer (as introducer) has approved the introduction. */\n viewerApproved?: boolean;\n /** Full user record for the candidate (needed for socials / Telegram fallback). */\n candidateUser?: UserRecord | null;\n /** Whether the counterpart is a ghost (not yet onboarded) user. */\n isGhost?: boolean;\n /** Narrator chip for home card display (name + remark, with optional avatar/userId for introducer). */\n narratorChip?: {\n name: string;\n text: string;\n avatar?: string | null;\n userId?: string;\n };\n /** Second party in introducer arrow layout (candidate -> secondParty). Present when viewer is introducer. */\n secondParty?: {\n name: string;\n avatar?: string | null;\n userId?: string;\n };\n}\n\n/** One step for debug visibility (subgraph/subtask). */\nexport interface DiscoverDebugStep {\n step: string;\n detail?: string;\n /** Structured data for rich display (e.g., candidate counts, scores). */\n data?: Record<string, unknown>;\n}\n\n/** One existing connection (no new opportunity created; user already has one with this person). */\nexport interface ExistingConnection {\n userId: string;\n name: string;\n status?: string;\n opportunityId?: string;\n}\n\n/** Statuses for which an existing connection may be shown as a card; others (accepted, rejected, expired) are only mentioned in text. */\nconst EXISTING_CONNECTION_CARD_STATUSES = ['draft', 'latent', 'pending'] as const;\n\nexport interface DiscoverResult {\n found: boolean;\n count: number;\n message?: string;\n opportunities?: FormattedDiscoveryCandidate[];\n /** Existing connections eligible for card display (draft, latent, or pending). Others are mention-only. */\n existingConnections?: ExistingConnection[];\n /** All existing connections for mention text (e.g. \"You already have a connection with: X (pending), Y (draft).\"). */\n existingConnectionsForMention?: ExistingConnection[];\n /**\n * Orchestrator-only: accepted opportunities the persist step found between the\n * discoverer and a candidate counterparty (status='accepted'). Populated from\n * OpportunityGraphState.dedupAlreadyAccepted. Used by the discover_opportunities\n * tool to tell the LLM \"this pair is already connected — open the existing\n * chat rather than creating a new draft\". Empty for the ambient trigger.\n */\n alreadyAcceptedPairs?: Array<{ opportunityId: string; counterpartyUserId: string }>;\n /** When true, the chat agent should call create_intent(suggestedIntentDescription) and retry discovery. */\n createIntentSuggested?: boolean;\n /** Description to pass to create_intent when createIntentSuggested is true. */\n suggestedIntentDescription?: string;\n /** Internal steps for copy-debug (select_strategies, opportunity_graph, enrich, etc.). */\n debugSteps?: DiscoverDebugStep[];\n /** Pagination metadata -- present when there are more unevaluated candidates. */\n pagination?: {\n discoveryId: string;\n evaluated: number;\n remaining: number;\n };\n /** 0–3 decision questions produced by the orchestrator path. Omitted when none. */\n questions?: Question[];\n /** Debug metadata for `debugMeta.discoveryQuestions` plumbing. */\n discoveryQuestionsDebug?: {\n inputMode: \"transcripts\" | \"insights\";\n finalCount: number;\n strategies: QuestionStrategy[];\n durationMs: number;\n };\n}\n\n/** Input for the shared enrichment helper. */\ninterface EnrichOpportunitiesInput {\n opportunities: Opportunity[];\n database: ChatGraphCompositeDatabase;\n userId: string;\n chatSessionId?: string;\n minimalForChat?: boolean;\n presenter?: OpportunityPresenter;\n useHomeCardFormat?: boolean;\n debugSteps: DiscoverDebugStep[];\n /** IDs of pre-existing opportunities merged into the list; these preserve their real status. */\n existingOpportunityIds?: Set<string>;\n /** When set, bypass the embedding filter for this specific user (direct connection mode). */\n targetUserId?: string;\n}\n\n/**\n * Enrich raw opportunities with profile data, presentation (LLM or minimal),\n * and narrator chips. Shared by both `runDiscoverFromQuery` and `continueDiscovery`\n * to avoid duplicating the profile-lookup / presenter / card-formatting logic.\n *\n * @param input - Enrichment context (opportunities, database, viewer, presentation options).\n * @returns Formatted discovery candidates ready for chat or home card display.\n */\nasync function enrichOpportunities(\n input: EnrichOpportunitiesInput,\n): Promise<FormattedDiscoveryCandidate[]> {\n const {\n opportunities,\n database,\n userId,\n chatSessionId,\n minimalForChat,\n presenter,\n useHomeCardFormat,\n debugSteps,\n existingOpportunityIds,\n targetUserId,\n } = input;\n\n const baseEnrichedRaw = await Promise.all(\n opportunities.map(async (opp) => {\n const viewerIsIntroducer = opp.actors.some((a) => a.role === 'introducer' && a.userId === userId);\n // When the viewer is the introducer, the \"candidate\" for the card is the agent\n // (the discovered person), not the patient (the intro target / onBehalfOfUserId).\n // For non-introducer views, pick the first non-viewer, non-introducer actor.\n const nonViewerNonIntroducerActors = opp.actors.filter((a) => a.userId !== userId && a.role !== 'introducer');\n const candidateActor = viewerIsIntroducer\n ? (nonViewerNonIntroducerActors.find((a) => a.role === 'agent') ?? nonViewerNonIntroducerActors[0])\n : nonViewerNonIntroducerActors[0];\n const candidateUserId = candidateActor?.userId ?? \"\";\n const viewerActor = opp.actors.find((a) => a.userId === userId);\n const [profile, candidateUser] = candidateUserId\n ? await Promise.all([database.getProfile(candidateUserId), database.getUser(candidateUserId)])\n : [null, null];\n // Skip soft-deleted users (deletedAt is set)\n if (candidateUser && 'deletedAt' in candidateUser && candidateUser.deletedAt) return null;\n const isDirectTarget = targetUserId && candidateUserId === targetUserId;\n if (!isDirectTarget && !candidateUser?.isGhost && !profile) return null;\n const confidence =\n typeof opp.interpretation?.confidence === \"number\"\n ? opp.interpretation.confidence\n : parseFloat(String(opp.interpretation?.confidence ?? 0)) || 0;\n return {\n opportunity: opp,\n candidateUserId,\n viewerRole: viewerActor?.role ?? \"party\",\n viewerApproved: viewerActor?.approved === true,\n candidateUser,\n profile,\n confidence,\n };\n }),\n );\n const baseEnriched = baseEnrichedRaw.filter((item): item is NonNullable<typeof item> => item !== null);\n debugSteps.push({\n step: \"enrich_profiles\",\n detail: `${baseEnriched.length} profile(s)`,\n });\n\n // Batch-fetch user records (candidates, introducers, and other party actors) for name/avatar fallback.\n const allActorUserIds = new Set<string>();\n for (const item of baseEnriched) {\n for (const actor of item.opportunity.actors) {\n if (actor.userId && actor.userId !== userId) {\n allActorUserIds.add(actor.userId);\n }\n }\n }\n const candidateUserIds = [...allActorUserIds];\n const [viewerUser, ...userResults] = await Promise.all([\n database.getUser(userId),\n ...candidateUserIds.map((id) => database.getUser(id)),\n ]);\n const avatarByUserId = new Map<string, string | null>();\n const nameByUserId = new Map<string, string | null>();\n const isGhostByUserId = new Map<string, boolean>();\n candidateUserIds.forEach((id, i) => {\n const user = userResults[i] ?? null;\n avatarByUserId.set(id, user?.avatar ?? null);\n nameByUserId.set(id, user?.name ?? null);\n isGhostByUserId.set(id, user?.isGhost ?? false);\n });\n const viewerName = viewerUser?.name ?? undefined;\n\n // Retry name resolution for candidates whose name is still missing.\n // The profile or user record may not have been ready on the first fetch\n // (e.g. profile generation still in flight). One retry covers transient gaps.\n const missingNameIds = baseEnriched\n .map((item) => item.candidateUserId)\n .filter((id) => id && !nameByUserId.get(id) && !baseEnriched.find((b) => b.candidateUserId === id && b.profile?.identity?.name));\n if (missingNameIds.length > 0) {\n const retried = await Promise.all(\n missingNameIds.map(async (id) => {\n const [profile, user] = await Promise.all([\n database.getProfile(id),\n database.getUser(id),\n ]);\n return { id, profile, user };\n }),\n );\n for (const r of retried) {\n const name = r.profile?.identity?.name ?? r.user?.name ?? null;\n if (name) nameByUserId.set(r.id, name);\n // Also update the baseEnriched profile so counterpartName picks it up\n if (r.profile) {\n const item = baseEnriched.find((b) => b.candidateUserId === r.id);\n if (item && !item.profile) item.profile = r.profile;\n }\n if (r.user?.avatar && !avatarByUserId.get(r.id)) {\n avatarByUserId.set(r.id, r.user.avatar);\n }\n }\n logger.verbose(\"[enrichOpportunities] Retried name lookup for candidates with missing names\", {\n attempted: missingNameIds.length,\n resolved: retried.filter((r) => r.profile?.identity?.name ?? r.user?.name).length,\n });\n }\n\n let presentations: OpportunityPresentationResult[] | undefined;\n let homeCardPresentations: HomeCardPresentationResult[] | undefined;\n let presenterContexts:\n | (Awaited<ReturnType<typeof gatherPresenterContext>> | MinimalPresenterContext)[]\n | undefined;\n\n if (minimalForChat && baseEnriched.length > 0) {\n // Minimal path: no LLM, viewer-centric card text (introduce counterpart to viewer)\n const counterpartName = (n: {\n profile?: { identity?: { name?: string } } | null;\n candidateUserId: string;\n }) => n.profile?.identity?.name ?? nameByUserId.get(n.candidateUserId) ?? \"\";\n homeCardPresentations = baseEnriched.map((item) => {\n const name = counterpartName(item)?.trim();\n const reasoning = item.opportunity.interpretation?.reasoning ?? \"\";\n const introducerName = item.opportunity.detection?.createdByName ?? undefined;\n const viewerIsIntroducer = item.opportunity.actors.some(\n (a) => a.role === \"introducer\" && a.userId === userId,\n );\n\n // For introducer view, find the second party (target user) name\n let secondPartyName: string | undefined;\n if (viewerIsIntroducer) {\n const otherPartyActors = item.opportunity.actors.filter(\n (a) => a.role !== \"introducer\" && a.userId !== item.candidateUserId,\n );\n if (otherPartyActors.length > 0) {\n const otherUserId = otherPartyActors[0].userId;\n secondPartyName = nameByUserId.get(otherUserId) ?? undefined;\n }\n }\n\n const isCounterpartGhost = isGhostByUserId.get(item.candidateUserId) ?? false;\n const personalizedSummary = viewerCentricCardSummary(\n reasoning,\n name,\n MINIMAL_MAIN_TEXT_MAX_CHARS,\n viewerName,\n introducerName,\n );\n return {\n headline: viewerIsIntroducer && secondPartyName\n ? `${name} → ${secondPartyName}`\n : (name ? `Connection with ${name}` : \"Suggested connection\"),\n personalizedSummary,\n digestSummary: name\n ? `You might like meeting ${name} based on your current interests.`\n : \"This connection may be relevant to your current interests.\",\n suggestedAction: \"Start a conversation to connect.\",\n narratorRemark: narratorRemarkFromReasoning(reasoning, name, viewerName),\n primaryActionLabel: getPrimaryActionLabel(viewerIsIntroducer ? \"introducer\" : \"party\"),\n secondaryActionLabel: SECONDARY_ACTION_LABEL,\n mutualIntentsLabel: \"Suggested connection\",\n greeting: \"\",\n };\n });\n presenterContexts = baseEnriched.map((item) => ({\n introducerName: item.opportunity.detection.createdByName ?? undefined,\n })) as MinimalPresenterContext[];\n } else if (presenter && baseEnriched.length > 0) {\n try {\n presenterContexts = await Promise.all(\n baseEnriched.map(({ opportunity }) =>\n gatherPresenterContext(database, opportunity, userId),\n ),\n );\n\n if (useHomeCardFormat) {\n // Use full home card format with action labels, narrator remark, etc.\n const fullContexts = presenterContexts as Awaited<\n ReturnType<typeof gatherPresenterContext>\n >[];\n const homeCardInputs: HomeCardPresenterInput[] = fullContexts.map(\n (ctx, idx) => ({\n ...ctx,\n mutualIntentCount: undefined,\n opportunityStatus: baseEnriched[idx].opportunity.status,\n }),\n );\n const llmResults = await presenter.presentHomeCardBatch(\n homeCardInputs,\n { concurrency: 5 },\n );\n // Append hardcoded button labels to LLM results\n homeCardPresentations = llmResults.map((llm, idx) => ({\n ...llm,\n primaryActionLabel: getPrimaryActionLabel(baseEnriched[idx].viewerRole),\n secondaryActionLabel: SECONDARY_ACTION_LABEL,\n }));\n } else {\n // Use basic presentation format\n presentations = await presenter.presentBatch(\n presenterContexts as Awaited<\n ReturnType<typeof gatherPresenterContext>\n >[],\n {\n concurrency: 5,\n },\n );\n }\n } catch (error) {\n logger.warn(\n \"Presenter enrichment failed during opportunity discovery; returning base results without presentations\",\n {\n userId,\n opportunitiesCount: baseEnriched.length,\n useHomeCardFormat,\n error: error instanceof Error ? error.message : String(error),\n },\n );\n presentations = undefined;\n homeCardPresentations = undefined;\n }\n }\n\n const enriched: FormattedDiscoveryCandidate[] = baseEnriched.map(\n (item, idx) => {\n const homeCard = homeCardPresentations?.[idx];\n const ctx = presenterContexts?.[idx];\n\n // Build narrator chip for home card format\n let narratorChip: FormattedDiscoveryCandidate[\"narratorChip\"];\n if (homeCard) {\n const viewerIsIntroducer = item.opportunity.actors.some(\n (a) => a.role === \"introducer\" && a.userId === userId,\n );\n if (viewerIsIntroducer) {\n narratorChip = {\n name: \"You\",\n text: homeCard.narratorRemark,\n userId: userId,\n };\n } else {\n const introducerActor = item.opportunity.actors.find(\n (a) => a.role === \"introducer\" && a.userId !== userId,\n );\n if (introducerActor) {\n const introducerName =\n ctx?.introducerName ??\n nameByUserId.get(introducerActor.userId) ??\n \"Someone\";\n narratorChip = {\n name: introducerName,\n text: homeCard.narratorRemark,\n userId: introducerActor.userId,\n avatar: avatarByUserId.get(introducerActor.userId) ?? null,\n };\n } else {\n narratorChip = {\n name: \"Index\",\n text: homeCard.narratorRemark,\n };\n }\n }\n }\n\n const isGhost = isGhostByUserId.get(item.candidateUserId) ?? false;\n\n // Build secondParty for introducer view (the other non-introducer party)\n let secondParty: FormattedDiscoveryCandidate[\"secondParty\"];\n const viewerIsIntroducerForCard = item.opportunity.actors.some(\n (a) => a.role === \"introducer\" && a.userId === userId,\n );\n if (viewerIsIntroducerForCard) {\n const otherPartyActor = item.opportunity.actors.find(\n (a) => a.role !== \"introducer\" && a.userId !== item.candidateUserId,\n );\n if (otherPartyActor) {\n const otherName = nameByUserId.get(otherPartyActor.userId) ?? undefined;\n if (otherName) {\n secondParty = {\n name: otherName,\n avatar: avatarByUserId.get(otherPartyActor.userId) ?? null,\n userId: otherPartyActor.userId,\n };\n }\n }\n }\n\n return {\n opportunityId: item.opportunity.id,\n userId: item.candidateUserId,\n name: item.profile?.identity?.name ?? nameByUserId.get(item.candidateUserId) ?? undefined,\n avatar: avatarByUserId.get(item.candidateUserId) ?? null,\n bio: truncateForChat(item.profile?.identity?.bio),\n matchReason:\n truncateForChat(\n item.opportunity.interpretation?.reasoning ?? \"\",\n ) ?? \"\",\n score: item.confidence,\n status: chatSessionId && !existingOpportunityIds?.has(item.opportunity.id) ? \"draft\" : item.opportunity.status,\n viewerRole: item.viewerRole,\n viewerApproved: item.viewerApproved,\n candidateUser: item.candidateUser,\n isGhost,\n ...(presentations?.[idx] && { presentation: presentations[idx] }),\n ...(homeCard && {\n homeCardPresentation: homeCard,\n }),\n ...(narratorChip && { narratorChip }),\n ...(secondParty && { secondParty }),\n };\n },\n );\n debugSteps.push({\n step: \"format_cards\",\n detail: `${enriched.length} card(s)`,\n });\n\n return enriched;\n}\n\n/** Cached discovery session data stored in Redis. */\ninterface CachedDiscoverySession {\n candidates: CandidateMatch[];\n userId: string;\n onBehalfOfUserId?: string;\n query: string;\n indexScope: string[];\n options: OpportunityGraphOptions;\n /**\n * Carried across pagination so page 2+ stays on the same flow as page 1.\n * Without this, orchestrator runs would fall back to the 'ambient' default\n * mid-search and lose the shorter park window + accepted-pair dedup.\n */\n trigger?: 'ambient' | 'orchestrator';\n}\n\n/**\n * Run discovery from an ad-hoc query (e.g. \"find me a mentor\", \"who needs a React developer\").\n * The HyDE graph's LensInferrer automatically infers search lenses from the query.\n * Invokes the opportunity graph and returns formatted candidates suitable for chat display.\n */\nexport async function runDiscoverFromQuery(\n input: DiscoverInput,\n): Promise<DiscoverResult> {\n const {\n opportunityGraph,\n database,\n userId,\n query,\n indexScope,\n limit = 5,\n triggerIntentId,\n targetUserId,\n onBehalfOfUserId,\n chatSessionId,\n trigger,\n negotiateTimeoutMs,\n } = input;\n\n if (indexScope.length === 0) {\n return {\n found: false,\n count: 0,\n message:\n \"You need to join at least one network (community) to discover opportunities. Use read_networks to see available networks, or create one.\",\n };\n }\n\n const debugSteps: DiscoverDebugStep[] = [];\n\n // When query is empty, the opportunity graph uses the user's intents in scope (indexedIntents[0].payload)\n // Lens inference is handled automatically by the HyDE graph's LensInferrer\n const queryOrEmpty = query?.trim() ?? \"\";\n // Orchestrator discovery defers the initial status to the graph's\n // trigger-aware `resolveInitialStatus`, which opens at 'negotiating' so\n // the accepted-draft streaming flow can run. Ambient chat discovery still\n // wants the legacy 'draft' status so the chat-only lifecycle holds; other\n // ambient callers keep 'latent'.\n const isOrchestrator = trigger === 'orchestrator';\n const options: OpportunityGraphOptions = {\n limit,\n ...(!isOrchestrator && { initialStatus: chatSessionId ? \"draft\" : \"latent\" }),\n ...(chatSessionId ? { conversationId: chatSessionId } : {}),\n ...(negotiateTimeoutMs !== undefined && { negotiateTimeoutMs }),\n };\n\n return withCallLogging(\n logger,\n \"runDiscoverFromQuery\",\n {\n userId,\n queryPreview: queryOrEmpty\n ? queryOrEmpty.substring(0, 50)\n : \"(using user intents in scope)\",\n indexScopeCount: indexScope.length,\n limit,\n },\n async () => {\n const result = await invokeWithAbortSignal(opportunityGraph, {\n userId,\n searchQuery: queryOrEmpty || undefined,\n // A single index resolves to the strict networkId override (membership-\n // validated in the scope node). Multiple indexes (e.g. a network-scoped\n // agent's bound network + personal index) pass through as indexScope so\n // the graph stays bounded instead of falling back to all networks.\n networkId: indexScope.length === 1 ? indexScope[0] : undefined,\n ...(indexScope.length > 1 ? { indexScope } : {}),\n triggerIntentId,\n targetUserId,\n onBehalfOfUserId,\n options,\n ...(trigger && { trigger }),\n });\n\n // Extract trace from graph and append to debugSteps\n const graphTrace = Array.isArray(result.trace) ? result.trace : [];\n for (const t of graphTrace) {\n debugSteps.push({\n step: t.node,\n detail: t.detail,\n ...(t.data ? { data: t.data } : {}),\n });\n }\n\n // Bail early if the graph returned an error\n if (result.error) {\n logger.warn(\"runDiscoverFromQuery graph returned error\", { error: result.error });\n return {\n found: false,\n count: 0,\n message: \"Failed to find opportunities. Please try again.\",\n debugSteps,\n };\n }\n\n // Cache remaining candidates for pagination\n let pagination: DiscoverResult['pagination'] | undefined;\n const remainingCandidates: CandidateMatch[] = result.remainingCandidates || [];\n if (remainingCandidates.length > 0 && input.cache) {\n try {\n const discoveryId = crypto.randomUUID();\n const cacheKey = `discovery:${userId}:${discoveryId}`;\n await input.cache.set(cacheKey, {\n candidates: remainingCandidates,\n userId,\n onBehalfOfUserId,\n query: queryOrEmpty,\n indexScope,\n options,\n ...(trigger && { trigger }),\n } satisfies CachedDiscoverySession, { ttl: 1800 }); // 30 minutes\n pagination = {\n discoveryId,\n evaluated: (result.candidates?.length ?? 0) - remainingCandidates.length,\n remaining: remainingCandidates.length,\n };\n } catch (cacheErr) {\n logger.warn(\"Failed to cache discovery pagination\", {\n userId,\n error: cacheErr instanceof Error ? cacheErr.message : String(cacheErr),\n });\n }\n }\n\n // Refine phase: a sibling of the opportunity graph in the trace tree.\n // Holds the three post-discovery summarization steps. Each step is its\n // own traced agent so it appears as a leaf in the trace UI.\n //\n // Negotiation summary: compress each raw negotiation into a fixed-size\n // structured digest so the question generator's prompt stays small\n // (a 10-candidate turn used to balloon past 60 KB and stall upstream).\n // Decision questions: generate up to 3 clarifying questions from the\n // digests + chat context.\n const { questionPayload } = await tracePhase(\"Refine\", async () => {\n const negotiationDigests = await summarizeNegotiations({\n negotiations: result.discoveryNegotiations ?? [],\n summarizer: input.negotiationSummary,\n enableQuestions: input.enableQuestions ?? false,\n trigger,\n });\n const questionPayload = await maybeBuildQuestions({\n trigger,\n enableQuestions: input.enableQuestions ?? false,\n chatSummary: input.chatSummary,\n questionGenerator: input.questionGenerator,\n chatSessionId,\n graphResult: result,\n negotiationDigests,\n query: queryOrEmpty,\n questionerEnqueue: input.questionerEnqueue,\n userId: input.userId,\n userContext: input.userId\n ? ((await input.database.getUserContext(input.userId, null))?.text ?? '')\n : '',\n });\n return { negotiationDigests, questionPayload };\n });\n\n if (result.createIntentSuggested && result.suggestedIntentDescription) {\n if (chatSessionId) {\n return {\n found: false,\n count: 0,\n message: \"No matching opportunities found. Try a different query.\",\n pagination,\n ...(questionPayload.questions !== undefined ? { questions: questionPayload.questions } : {}),\n ...(questionPayload.debug !== undefined ? { discoveryQuestionsDebug: questionPayload.debug } : {}),\n };\n }\n return {\n found: false,\n count: 0,\n createIntentSuggested: true,\n suggestedIntentDescription: result.suggestedIntentDescription,\n message:\n \"No matching opportunities; add an intent with the suggested description to improve discovery.\",\n debugSteps,\n pagination,\n ...(questionPayload.questions !== undefined ? { questions: questionPayload.questions } : {}),\n ...(questionPayload.debug !== undefined ? { discoveryQuestionsDebug: questionPayload.debug } : {}),\n };\n }\n\n let opportunities: Opportunity[] = Array.isArray(result.opportunities)\n ? result.opportunities\n : [];\n let existingOpportunityIds: Set<string> | undefined;\n const rawExistingBetweenActors = Array.isArray(result.existingBetweenActors)\n ? result.existingBetweenActors\n : [];\n // Orchestrator trigger populates this; ambient returns []. Kept as a\n // loosely-typed pass-through because DiscoverResult is consumed by\n // callers (chat tool, tests) that already model the narrower shape.\n const alreadyAcceptedPairs = Array.isArray(\n (result as { dedupAlreadyAccepted?: Array<{ opportunityId: string; counterpartyUserId: string }> })\n .dedupAlreadyAccepted,\n )\n ? (result as { dedupAlreadyAccepted: Array<{ opportunityId: string; counterpartyUserId: string }> })\n .dedupAlreadyAccepted\n : [];\n // Enrich existing-between-actors with names so the tool can say \"You already have a connection with X (pending).\"\n const existingConnections: ExistingConnection[] = await Promise.all(\n rawExistingBetweenActors.map(async (item) => {\n const user = await database.getUser(item.candidateUserId);\n return {\n userId: item.candidateUserId,\n name: user?.name ?? \"Someone\",\n ...(item.existingStatus ? { status: item.existingStatus } : {}),\n ...(item.existingOpportunityId ? { opportunityId: item.existingOpportunityId } : {}),\n };\n }),\n );\n if (existingConnections.length > 0) {\n logger.verbose(\"[runDiscoverFromQuery] Skipped duplicates; existing connections\", {\n count: existingConnections.length,\n userIds: existingConnections.map((c) => c.userId),\n });\n }\n // Only expose existing connections as cards when status is in EXISTING_CONNECTION_CARD_STATUSES (draft, latent, pending); others are mention-only.\n const existingConnectionsForCards = existingConnections.filter((c) =>\n c.status != null && EXISTING_CONNECTION_CARD_STATUSES.includes(c.status as typeof EXISTING_CONNECTION_CARD_STATUSES[number])\n );\n\n // Fetch full opportunity data for existing connections that should be shown as cards\n // and merge them with the newly created opportunities\n if (existingConnectionsForCards.length > 0) {\n const existingOpps = await Promise.all(\n existingConnectionsForCards\n .filter((c) => c.opportunityId)\n .map((c) => database.getOpportunity(c.opportunityId!))\n );\n const validExistingOpps = existingOpps.filter((o): o is Opportunity => o != null);\n if (validExistingOpps.length > 0) {\n logger.verbose(\"[runDiscoverFromQuery] Including existing opportunities as cards\", {\n count: validExistingOpps.length,\n ids: validExistingOpps.map((o) => o.id),\n });\n existingOpportunityIds = new Set(validExistingOpps.map((o) => o.id));\n opportunities = [...opportunities, ...validExistingOpps];\n }\n }\n\n // Chat discovery: when we have chatSessionId we just invoked the graph; all result.opportunities\n // were created in this call and belong to this session. Do not filter by status: the enricher\n // may set status to pending/latent when merging with related opportunities, so filtering to\n // \"draft\" would incorrectly drop them.\n if (chatSessionId && (result.opportunities?.length ?? 0) > 0) {\n logger.verbose(\"[runDiscoverFromQuery] Chat session opportunities from graph\", {\n count: opportunities.length,\n statuses: opportunities.map((o) => o.status),\n });\n }\n debugSteps.push({\n step: \"opportunity_graph\",\n detail: `${opportunities.length} opportunity(ies)${existingConnections.length > 0 ? `, ${existingConnections.length} existing` : \"\"}`,\n });\n\n if (opportunities.length === 0) {\n if (existingConnections.length > 0) {\n return {\n found: true,\n count: 0,\n message:\n \"No new opportunities created; you already have a connection with: \" +\n existingConnections.map((c) => `${c.name}${c.status ? ` (${c.status})` : \"\"}`).join(\", \") +\n \". View on your home page.\",\n existingConnections: existingConnectionsForCards,\n existingConnectionsForMention: existingConnections,\n ...(alreadyAcceptedPairs.length > 0 && { alreadyAcceptedPairs }),\n debugSteps,\n pagination,\n ...(questionPayload.questions !== undefined ? { questions: questionPayload.questions } : {}),\n ...(questionPayload.debug !== undefined ? { discoveryQuestionsDebug: questionPayload.debug } : {}),\n };\n }\n return {\n found: false,\n count: 0,\n message:\n \"No matching opportunities found. Try a different query or create intents to improve matching.\",\n ...(alreadyAcceptedPairs.length > 0 && { alreadyAcceptedPairs }),\n debugSteps,\n pagination,\n ...(questionPayload.questions !== undefined ? { questions: questionPayload.questions } : {}),\n ...(questionPayload.debug !== undefined ? { discoveryQuestionsDebug: questionPayload.debug } : {}),\n };\n }\n\n const enriched = await enrichOpportunities({\n opportunities,\n database,\n userId,\n chatSessionId,\n minimalForChat: input.minimalForChat,\n presenter: input.presenter,\n useHomeCardFormat: input.useHomeCardFormat,\n debugSteps,\n existingOpportunityIds,\n targetUserId,\n });\n\n return {\n found: true,\n count: enriched.length,\n opportunities: enriched,\n ...(existingConnectionsForCards.length > 0 ? { existingConnections: existingConnectionsForCards } : {}),\n ...(existingConnections.length > 0 ? { existingConnectionsForMention: existingConnections } : {}),\n ...(alreadyAcceptedPairs.length > 0 ? { alreadyAcceptedPairs } : {}),\n debugSteps,\n pagination,\n ...(questionPayload.questions !== undefined ? { questions: questionPayload.questions } : {}),\n ...(questionPayload.debug !== undefined ? { discoveryQuestionsDebug: questionPayload.debug } : {}),\n };\n },\n { context: { userId }, logOutput: false },\n ).catch((err) => {\n return {\n found: false,\n count: 0,\n message: \"Failed to find opportunities. Please try again.\",\n };\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// DECISION-QUESTION HELPER\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype GraphResultLike = {\n sourceProfile?: SourceProfileData | null;\n discoveryNegotiations?: DiscoveryNegotiation[];\n discoverySummary?: DiscoverySummary | null;\n};\n\ninterface MaybeBuildQuestionsInput {\n trigger: 'ambient' | 'orchestrator' | undefined;\n enableQuestions: boolean;\n chatSummary: ChatSummaryReader | undefined;\n questionGenerator: QuestionGeneratorReader | undefined;\n chatSessionId: string | undefined;\n graphResult: GraphResultLike;\n /** Pre-built per-negotiation digests. Pass [] when summarization is unavailable or disabled. */\n negotiationDigests: DiscoveryNegotiationDigest[];\n query: string;\n /** Optional async enqueue callback for background question generation. */\n questionerEnqueue?: DiscoverInput['questionerEnqueue'];\n /** User ID needed for the enqueue payload. */\n userId?: string;\n /** The seeker's global user_context paragraph (profile-replacing identity text). */\n userContext?: string;\n}\n\n/**\n * Run the negotiation summarizer over every negotiation in this discovery turn.\n * Each summarization is independent — run them concurrently via Promise.all.\n * When the summarizer is missing (no LLM available) or fails for an individual\n * negotiation, fall back to a deterministic digest so the downstream generator\n * still has structured input.\n */\nasync function summarizeNegotiations(args: {\n negotiations: DiscoveryNegotiation[];\n summarizer: NegotiationSummaryReader | undefined;\n enableQuestions: boolean;\n trigger: 'ambient' | 'orchestrator' | undefined;\n}): Promise<DiscoveryNegotiationDigest[]> {\n // Skip the LLM round-trip entirely when questions won't be built.\n if (!args.enableQuestions || args.trigger !== 'orchestrator') return [];\n if (args.negotiations.length === 0) return [];\n\n const perNegTimeoutMs = parsePositiveIntEnv(\n \"NEGOTIATION_SUMMARY_TIMEOUT_MS\",\n NEGOTIATION_SUMMARY_TIMEOUT_MS_DEFAULT,\n );\n const callerSignal = requestContext.getStore()?.abortSignal;\n\n return traceAgent(\n `Negotiation summary (${args.negotiations.length})`,\n () =>\n Promise.all(\n args.negotiations.map(async (n) => {\n if (!args.summarizer) return buildFallbackDigest(n);\n // Per-negotiation deadline: one slow OpenRouter route used to\n // dominate the post-discovery tail. With a cap, an aborted\n // summarizer falls back to a deterministic digest so the\n // question generator still has structured input.\n const signal = combineWithDeadline(callerSignal, perNegTimeoutMs);\n try {\n const d = await args.summarizer.summarize(n, { signal });\n return d ?? buildFallbackDigest(n);\n } catch (err) {\n // Attribute cause from err.name (AbortError), not from\n // signal.aborted — the latter is read post-catch and can race a\n // deadline-trip-after-unrelated-error, producing a misleading log.\n const aborted = err instanceof Error && err.name === \"AbortError\";\n logger.warn(\"negotiationSummary.summarize threw — using fallback digest\", {\n counterpartyHint: n.counterpartyHint,\n aborted,\n error: err instanceof Error ? err.message : String(err),\n });\n return buildFallbackDigest(n);\n }\n }),\n ),\n (digests) => `${digests.length} digest${digests.length === 1 ? \"\" : \"s\"}`,\n );\n}\n\nasync function maybeBuildQuestions(args: MaybeBuildQuestionsInput): Promise<{\n questions?: Question[];\n debug?: DiscoverResult[\"discoveryQuestionsDebug\"];\n}> {\n if (!args.enableQuestions) return {};\n if (args.trigger !== 'orchestrator') return {};\n\n // Hardcoded — `insights` mode is planned for a later slice. Warn if the env\n // var is set so operators aren't surprised when reporting still says\n // \"transcripts\".\n if (process.env.DISCOVERY_QUESTIONS_INPUT_MODE === \"insights\") {\n logger.warn(\"DISCOVERY_QUESTIONS_INPUT_MODE=insights is not yet implemented; falling back to transcripts\");\n }\n const inputMode: \"transcripts\" | \"insights\" = \"transcripts\";\n\n let chatContext: ChatContextDigest | undefined;\n if (args.chatSummary && args.chatSessionId) {\n const sessionId = args.chatSessionId;\n const summary = args.chatSummary;\n chatContext = await traceAgent(\n \"Chat summary\",\n async () => {\n try {\n return (await summary.getDigest(sessionId)) ?? undefined;\n } catch (err) {\n logger.warn(\"chatSummary.getDigest threw — proceeding without digest\", {\n sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n return undefined;\n }\n },\n (digest) => (digest ? \"loaded\" : \"empty\"),\n );\n }\n\n // ── Async enqueue path ──────────────────────────────────────────────────\n // When questionerEnqueue is provided, dispatch question generation\n // asynchronously to the background QuestionerQueue. This replaces the\n // inline generator path. Questions will be persisted to DB by the queue\n // worker and served via GET /api/questions.\n if (args.questionerEnqueue && args.userId) {\n const summary = args.graphResult.discoverySummary ?? {\n totalCandidates: 0,\n opportunitiesFound: 0,\n noOpportunityCount: 0,\n timeoutCount: 0,\n roleDistribution: {},\n };\n\n const enqueueInput = buildDiscoveryQuestionInput({\n query: args.query,\n userContext: args.userContext ?? '',\n negotiationDigests: args.negotiationDigests,\n summary,\n chatContext,\n now: new Date().toISOString(),\n });\n\n try {\n await args.questionerEnqueue({\n mode: 'discovery',\n userId: args.userId,\n sourceType: 'discovery',\n sourceId: args.chatSessionId ?? crypto.randomUUID(),\n context: enqueueInput,\n conversationId: args.chatSessionId,\n });\n logger.info(\"Question generation enqueued to QuestionerQueue\", {\n userId: args.userId,\n trigger: args.trigger,\n });\n } catch (err) {\n logger.warn(\"Failed to enqueue question generation\", {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n return {};\n }\n\n // ── Inline generator path (backward compat) ────────────────────────────\n if (!args.questionGenerator) return {};\n\n const negotiationDigests = args.negotiationDigests;\n const summary = args.graphResult.discoverySummary ?? {\n totalCandidates: 0,\n opportunitiesFound: 0,\n noOpportunityCount: 0,\n timeoutCount: 0,\n roleDistribution: {},\n };\n\n const input = buildDiscoveryQuestionInput({\n query: args.query,\n userContext: args.userContext ?? '',\n negotiationDigests,\n summary,\n chatContext,\n now: new Date().toISOString(),\n });\n\n const questionGenerator = args.questionGenerator;\n const generatorStart = Date.now();\n const questionsTimeoutMs = parsePositiveIntEnv(\n \"DISCOVERY_QUESTIONS_TIMEOUT_MS\",\n DISCOVERY_QUESTIONS_TIMEOUT_MS_DEFAULT,\n );\n const questionsSignal = combineWithDeadline(\n requestContext.getStore()?.abortSignal,\n questionsTimeoutMs,\n );\n const genResult = await traceAgent(\n \"Decision questions\",\n async () => {\n try {\n return await questionGenerator.generate(input, { signal: questionsSignal });\n } catch (err) {\n logger.warn(\"questionGenerator.generate threw — suppressing questions\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n },\n (r) => {\n const count = r?.questions?.length ?? 0;\n return `${count} question${count === 1 ? \"\" : \"s\"}`;\n },\n );\n const durationMs = Date.now() - generatorStart;\n\n const finalCount = genResult?.questions?.length ?? 0;\n const strategies: QuestionStrategy[] = genResult?.strategies ?? [];\n\n return {\n ...(genResult && genResult.questions.length > 0 ? { questions: genResult.questions } : {}),\n debug: {\n inputMode,\n finalCount,\n strategies,\n durationMs,\n },\n };\n}\n\n/**\n * Continue a paginated discovery by evaluating the next batch of cached candidates.\n * Loads candidates from Redis, invokes the opportunity graph in continue_discovery mode,\n * then enriches and returns the results with updated pagination metadata.\n *\n * @param input - Continuation context (graph, database, cache, discoveryId, etc.).\n * @returns Discovery result with enriched opportunities and pagination state.\n */\nexport async function continueDiscovery(input: {\n opportunityGraph: CompiledOpportunityGraph;\n database: ChatGraphCompositeDatabase;\n cache: Cache;\n userId: string;\n discoveryId: string;\n /** If provided, validates the cached session's indexScope contains this index. */\n expectedIndexId?: string;\n limit?: number;\n chatSessionId?: string;\n minimalForChat?: boolean;\n presenter?: OpportunityPresenter;\n useHomeCardFormat?: boolean;\n}): Promise<DiscoverResult> {\n const {\n opportunityGraph,\n database,\n cache,\n userId,\n discoveryId,\n expectedIndexId,\n limit = 20,\n chatSessionId,\n } = input;\n const cacheKey = `discovery:${userId}:${discoveryId}`;\n\n const cached = await cache.get<CachedDiscoverySession>(cacheKey);\n\n if (!cached) {\n return {\n found: false,\n count: 0,\n message: \"Discovery session expired or not found. Please start a new search.\",\n };\n }\n\n // Validate that the cached session's scope matches the current chat context\n if (expectedIndexId && !cached.indexScope.includes(expectedIndexId)) {\n return {\n found: false,\n count: 0,\n message: \"Discovery session was created in a different context. Please start a new search.\",\n };\n }\n\n const debugSteps: DiscoverDebugStep[] = [];\n\n const result = await invokeWithAbortSignal(opportunityGraph, {\n userId,\n searchQuery: cached.query || undefined,\n candidates: cached.candidates,\n operationMode: 'continue_discovery' as const,\n onBehalfOfUserId: cached.onBehalfOfUserId,\n // Carry the original trigger so page 2+ stays on the same flow as page\n // 1 (orchestrator negotiations with 60s park window + accepted-pair\n // dedup, or ambient with 5-min park window).\n ...(cached.trigger && { trigger: cached.trigger }),\n options: {\n ...cached.options,\n limit,\n ...(chatSessionId ? { conversationId: chatSessionId } : {}),\n },\n });\n\n // Extract trace from graph and append to debugSteps\n const graphTrace = result.trace || [];\n for (const t of graphTrace) {\n debugSteps.push({\n step: t.node,\n detail: t.detail,\n ...(t.data ? { data: t.data } : {}),\n });\n }\n\n // Bail early if the graph returned an error\n if (result.error) {\n logger.warn(\"continueDiscovery graph returned error\", { error: result.error });\n return {\n found: false,\n count: 0,\n message: \"Discovery continuation failed. Please start a new search.\",\n debugSteps,\n };\n }\n\n // Update cache with remaining candidates or delete if exhausted\n const remaining: CandidateMatch[] = result.remainingCandidates || [];\n let pagination: DiscoverResult['pagination'] | undefined;\n try {\n if (remaining.length > 0) {\n await cache.set(cacheKey, {\n ...cached,\n candidates: remaining,\n } satisfies CachedDiscoverySession, { ttl: 1800 });\n pagination = {\n discoveryId,\n evaluated: cached.candidates.length - remaining.length,\n remaining: remaining.length,\n };\n } else {\n await cache.delete(cacheKey);\n }\n } catch (cacheErr) {\n logger.warn(\"Failed to update discovery pagination cache\", {\n userId,\n discoveryId,\n error: cacheErr instanceof Error ? cacheErr.message : String(cacheErr),\n });\n }\n\n // Check for opportunities in result\n const opportunities: Opportunity[] = Array.isArray(result.opportunities) ? result.opportunities : [];\n\n if (opportunities.length === 0) {\n return {\n found: false,\n count: 0,\n message: \"No more matching opportunities found in the remaining candidates.\",\n debugSteps,\n pagination,\n };\n }\n\n const enriched = await enrichOpportunities({\n opportunities,\n database,\n userId,\n chatSessionId,\n minimalForChat: input.minimalForChat,\n presenter: input.presenter,\n useHomeCardFormat: input.useHomeCardFormat,\n debugSteps,\n });\n\n return {\n found: true,\n count: enriched.length,\n opportunities: enriched,\n debugSteps,\n pagination,\n };\n}\n"]}
@@ -60,7 +60,11 @@ export interface DiscoverySummary {
60
60
  /** Map of role → count across all outcomes' `agreedRoles`. */
61
61
  roleDistribution: Partial<Record<NegotiationRole, number>>;
62
62
  }
63
- /** The seeker's profile slice the generator sees. All fields optional. */
63
+ /**
64
+ * The seeker's profile slice the generator used to see. Retained as an exported
65
+ * type for backward compatibility; the question prompt now consumes the global
66
+ * `userContext` paragraph instead of these discrete fields.
67
+ */
64
68
  export interface DiscoverySourceProfile {
65
69
  name?: string;
66
70
  bio?: string;
@@ -72,7 +76,8 @@ export interface DiscoverySourceProfile {
72
76
  export interface DiscoveryQuestionInput {
73
77
  /** The seeker's original natural-language query / signal that triggered discovery. */
74
78
  query: string;
75
- sourceProfile: DiscoverySourceProfile;
79
+ /** The seeker's global user_context paragraph (profile-replacing identity text). */
80
+ userContext: string;
76
81
  /**
77
82
  * Compact per-negotiation digests from THIS discovery turn. Each digest is a
78
83
  * fixed-size structured summary (counterparty hint, index, outcome role,
@@ -1 +1 @@
1
- {"version":3,"file":"question.prompt.d.ts","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC;AAEjG,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAE3D,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE;QAAE,OAAO,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,eAAe,CAAA;KAAE,CAAC;CAC1E;AAED,gCAAgC;AAChC,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC;IAC/D,0EAA0E;IAC1E,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACjC;AAED,2DAA2D;AAC3D,MAAM,WAAW,oBAAoB;IACnC,2FAA2F;IAC3F,cAAc,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,EAAE,gBAAgB,CAAC;IAC1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D;AAED,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4CAA4C;AAC5C,MAAM,WAAW,sBAAsB;IACrC,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,sBAAsB,CAAC;IACtC;;;;;OAKG;IACH,kBAAkB,EAAE,0BAA0B,EAAE,CAAC;IACjD,OAAO,EAAE,gBAAgB,CAAC;IAC1B,iEAAiE;IACjE,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2GAA2G;AAC3G,eAAO,MAAM,aAAa,yyLA0C0J,CAAC;AAErL;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAmCzE"}
1
+ {"version":3,"file":"question.prompt.d.ts","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC;AAEjG,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAE3D,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE;QAAE,OAAO,EAAE,eAAe,CAAC;QAAC,SAAS,EAAE,eAAe,CAAA;KAAE,CAAC;CAC1E;AAED,gCAAgC;AAChC,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC;IAC/D,0EAA0E;IAC1E,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACjC;AAED,2DAA2D;AAC3D,MAAM,WAAW,oBAAoB;IACnC,2FAA2F;IAC3F,cAAc,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,EAAE,gBAAgB,CAAC;IAC1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4CAA4C;AAC5C,MAAM,WAAW,sBAAsB;IACrC,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,kBAAkB,EAAE,0BAA0B,EAAE,CAAC;IACjD,OAAO,EAAE,gBAAgB,CAAC;IAC1B,iEAAiE;IACjE,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2GAA2G;AAC3G,eAAO,MAAM,aAAa,yyLA0C0J,CAAC;AAErL;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAmCzE"}
@@ -48,7 +48,7 @@ Output. Return at most 3 entries in the "questions" array. Each entry must inclu
48
48
  * Pure builder: assembles the user message string from a structured input.
49
49
  */
50
50
  export function buildQuestionPrompt(input) {
51
- const profileSummary = renderProfile(input.sourceProfile);
51
+ const profileSummary = input.userContext?.trim() || "(no profile data)";
52
52
  const connectionReviewBlocks = renderConnectionReviewDigests(input.negotiationDigests);
53
53
  const chatContextBlock = input.chatContext
54
54
  ? renderDigest(input.chatContext)
@@ -105,20 +105,6 @@ function renderConnectionReviewDigests(digests) {
105
105
  })
106
106
  .join("\n\n");
107
107
  }
108
- function renderProfile(p) {
109
- const lines = [];
110
- if (p.name)
111
- lines.push(`Name: ${p.name}`);
112
- if (p.bio)
113
- lines.push(`Bio: ${p.bio}`);
114
- if (p.location)
115
- lines.push(`Location: ${p.location}`);
116
- if (p.skills && p.skills.length > 0)
117
- lines.push(`Skills: ${p.skills.join(", ")}`);
118
- if (p.interests && p.interests.length > 0)
119
- lines.push(`Interests: ${p.interests.join(", ")}`);
120
- return lines.length > 0 ? lines.join("\n") : "(no profile data)";
121
- }
122
108
  function renderEngagementPattern(dist) {
123
109
  const parts = [];
124
110
  if ((dist.peer ?? 0) > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"question.prompt.js","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Prompt module for the decision-question generator: the system prompt\n * constant, the `DiscoveryQuestionInput` contract, and a pure string-building\n * `buildQuestionPrompt` that assembles the user message.\n *\n * Pure: no I/O, no LLM call. The generator class (`question.generator.ts`)\n * orchestrates this module + an LLM client.\n */\nimport type { ChatContextDigest } from \"../shared/schemas/chat-context.schema.js\";\nimport type { DiscoveryNegotiationDigest } from \"../shared/schemas/negotiation-digest.schema.js\";\n\n/** Roles used in the existing negotiation framework. */\nexport type NegotiationRole = \"agent\" | \"patient\" | \"peer\";\n\n/** One turn within a negotiation. */\nexport interface DiscoveryTurn {\n action: \"propose\" | \"accept\" | \"reject\" | \"counter\" | \"question\";\n reasoning: string;\n suggestedRoles: { ownUser: NegotiationRole; otherUser: NegotiationRole };\n}\n\n/** Outcome of a negotiation. */\nexport interface DiscoveryOutcome {\n hasOpportunity: boolean;\n reasoning: string;\n agreedRoles?: Array<{ userId: string; role: NegotiationRole }>;\n /** Why the negotiation stopped, when not by an explicit accept/reject. */\n reason?: \"turn_cap\" | \"timeout\";\n}\n\n/** One negotiation that ran during this discovery turn. */\nexport interface DiscoveryNegotiation {\n /** Opaque counterparty identifier; NEVER surfaced to the user (kept out of the prompt). */\n counterpartyId: string;\n /** Abstract profile slice for the LLM (e.g. \"AI infra founder, Berlin\"). */\n counterpartyHint: string;\n /** The network/community prompt this negotiation ran under. */\n indexContext: string;\n /** Last 6 turns are retained; earlier ones are dropped. */\n turns: DiscoveryTurn[];\n outcome: DiscoveryOutcome;\n /**\n * Optional pre-negotiation evaluator score (0..1). When more than\n * `MAX_NEGOTIATIONS` candidates exist, this is used as a tie-breaker after\n * `turns.length` to decide which to keep.\n */\n seedAssessmentScore?: number;\n}\n\n/** Aggregate counters across all negotiations in this discovery turn. */\nexport interface DiscoverySummary {\n totalCandidates: number;\n opportunitiesFound: number;\n noOpportunityCount: number;\n /** Subset of `noOpportunityCount` where the negotiation hit a turn-cap or timeout. */\n timeoutCount: number;\n /** Map of role → count across all outcomes' `agreedRoles`. */\n roleDistribution: Partial<Record<NegotiationRole, number>>;\n}\n\n/** The seeker's profile slice the generator sees. All fields optional. */\nexport interface DiscoverySourceProfile {\n name?: string;\n bio?: string;\n location?: string;\n skills?: string[];\n interests?: string[];\n}\n\n/** Full input to the question generator. */\nexport interface DiscoveryQuestionInput {\n /** The seeker's original natural-language query / signal that triggered discovery. */\n query: string;\n sourceProfile: DiscoverySourceProfile;\n /**\n * Compact per-negotiation digests from THIS discovery turn. Each digest is a\n * fixed-size structured summary (counterparty hint, index, outcome role,\n * keyTake) — pre-summarized so this prompt stays small regardless of how\n * many candidates were negotiated. Raw negotiations are NOT passed here.\n */\n negotiationDigests: DiscoveryNegotiationDigest[];\n summary: DiscoverySummary;\n /** Distilled chat-session digest, when a session is in scope. */\n chatContext?: ChatContextDigest;\n /** ISO timestamp used as the \"now\" anchor in the prompt. */\n now: string;\n}\n\n/** @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version. */\nexport const SYSTEM_PROMPT = `You help write user-facing follow-up questions after Index has reviewed potential connections for a human. Your job: surface the minimum set of structured decision questions the human must answer to make the next discovery turn sharper, or improve their outlook on the intent.\n\nYou may pick from five strategies. Choose contextually; mix when multiple questions genuinely complement.\n- refine_intent: ask the user to sharpen or pivot their original signal.\n- surface_missing_detail: ask for one concrete missing input (stage, location, timing, scope, …).\n- open_adjacent_thread: offer a pivot suggested by recurring connection signals.\n- reflective_summary: mirror what the connection review revealed and ask the user to decide.\n- surface_emergent_knowledge: cite a fact you learned from the connection review and ask the user to decide in light of it.\n\nAsk a question only when ALL of these hold:\n1. Index cannot resolve the decision autonomously from the evidence shown.\n2. The answer would materially change which people surface next.\n3. The same fact is NOT already in chatContext.statedFacts, NOT already asked in chatContext.openQuestions, and NOT already shared in chatContext.surfacedFindings.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the original query, discovery pattern, connection pattern, or concrete learned fact in the question text itself. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about. For example, prefer \"For your AI crypto decentralized deep-tech search, which area is most critical right now?\" over \"Which area is most critical right now?\"\n\nReferential closure. The prompt must resolve entirely on its own, with no dangling references. The reader sees ONLY the question text — never the people you reviewed, the events on their calendar, or this conversation. Do not use demonstratives or definite anaphora that point at things the reader cannot see: \"these builders\", \"those founders\", \"these researchers\", \"these conversations\", \"this lunch\", \"the speaker\". If you reference a person, name them. If you reference a group, restate the concrete shared attribute inside the question itself (\"founders working on decentralized identity\"), never \"these founders\". Never imply a list, set, or prior exchange the reader is not currently looking at.\n- Bad: \"What kind of collaboration are you looking for with these builders?\"\n- Good: \"You're meeting people building agent infrastructure — what kind of collaboration are you looking for?\"\n\nNo process narration. Never describe Index's own activity or internal state. Forbidden: \"the previous negotiation\", \"the negotiation stalled\", \"opportunities found so far\", \"my search\", \"the counterparty\", \"candidates reviewed\", restating why a match did or did not happen, or quoting words a counterparty did or did not use. Ask about the user's goal or intent directly, never about the matching pipeline.\n- Bad: \"All opportunities found so far are related to 'Edge Esmeralda'. Would you like to broaden the search?\"\n- Good: \"Do you want to focus on people at Edge Esmeralda, or also connect beyond it?\"\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first (e.g. one surface_emergent_knowledge + one refine_intent). Add a third only when there are ≥3 substantive people reviewed and three distinct strategies each unblock a real decision. Two questions of the same strategy are acceptable only if their decision domains differ (different titles). Avoid stacking three pulls (info-from-user); balance with pushes (info-to-user via reflective_summary / surface_emergent_knowledge).\n\nOrdering. Questions whose answer unblocks the most connection reviews come first; then highest-impact; then ambiguity-clarifying. Reviews that needed more detail or ran out of time signal under-specification — prioritize.\n\nUser-facing language. Every title, prompt, option label, and option description is shown directly to the user. Never mention raw protocol mechanics or internal labels such as \"agent\", \"patient\", \"peer\", \"suggestedRoles\", \"role distribution\", \"counterparty\", \"negotiation\", \"turn_cap\", \"timeout\", or \"candidate\". Use natural language instead: people, matches, connections, mutual collaboration, someone who can help, or someone seeking help.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest path with \" (Recommended)\" and list it first. The description states the CONSEQUENCE of choosing the option, not its definition. 2–4 options. Never add an \"Other\" option — clients provide a free-text fallback automatically. For surface_emergent_knowledge questions, anchor the prompt in the concrete cited fact (\"Multiple people flagged that…\") and let the options represent decisions in light of that fact, not different versions of the fact.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Discovery examples: \"Stage\", \"Timing\", \"Role\", \"Location\", \"Stack\", \"Budget\", \"Scope\", \"Format\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I look again?\").\n- Don't ask about hypothetical edge cases that didn't occur.\n- Don't ask about specific person identities; treat the provided person summary as the only allowed reference.\n- Don't repeat anything in chatContext.openQuestions.\n- Don't re-surface anything in chatContext.surfacedFindings.\n- Don't ask for facts in chatContext.statedFacts.\n\nOutput. Return at most 3 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the five values). If nothing is worth asking, return \"questions\": [].`;\n\n/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Pure builder: assembles the user message string from a structured input.\n */\nexport function buildQuestionPrompt(input: DiscoveryQuestionInput): string {\n const profileSummary = renderProfile(input.sourceProfile);\n const connectionReviewBlocks = renderConnectionReviewDigests(input.negotiationDigests);\n const chatContextBlock = input.chatContext\n ? renderDigest(input.chatContext)\n : \"(no chat context available)\";\n const engagementPattern = renderEngagementPattern(input.summary.roleDistribution);\n\n return [\n \"## Seeker's query\",\n input.query,\n \"\",\n \"## Seeker profile\",\n profileSummary,\n \"\",\n \"## This discovery turn\",\n `- ${input.summary.totalCandidates} people reviewed`,\n `- ${input.summary.opportunitiesFound} promising connections found`,\n `- ${input.summary.noOpportunityCount} reviews did not find enough fit (${input.summary.timeoutCount} needed more detail or time)`,\n `- Engagement pattern: ${engagementPattern}`,\n \"\",\n \"## Connection review evidence (compact digests)\",\n connectionReviewBlocks,\n \"\",\n \"## What the user has already said in this session\",\n chatContextBlock,\n \"\",\n \"## Now\",\n input.now,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of decision questions the seeker must answer to make\",\n \"the next discovery turn sharper. Apply every rule from your system prompt\",\n \"before outputting. Return an empty `questions` array if nothing is worth asking.\",\n ].join(\"\\n\");\n}\n\n/**\n * Render the negotiation-digest collection into compact one-liners. Each digest\n * is fixed-size (≤ ~400 chars after rendering), so the rendered block scales\n * linearly with candidate count: 10 candidates ≈ 4 KB, well within budget.\n */\nfunction renderConnectionReviewDigests(digests: DiscoveryNegotiationDigest[]): string {\n if (digests.length === 0) return \"(no connection reviews)\";\n return digests\n .map((d) => {\n const relationshipSignal = d.suggestedRoles\n ? [` Relationship signal: ${renderRelationshipSignal(d.suggestedRoles)}`]\n : [];\n return [\n `- Person: ${d.counterpartyHint}`,\n ` Community context: ${d.indexContext}`,\n ` Outcome: ${renderOutcome(d)}`,\n ...relationshipSignal,\n ` Take: ${d.keyTake}`,\n ].join(\"\\n\");\n })\n .join(\"\\n\\n\");\n}\n\nfunction renderProfile(p: DiscoverySourceProfile): string {\n const lines: string[] = [];\n if (p.name) lines.push(`Name: ${p.name}`);\n if (p.bio) lines.push(`Bio: ${p.bio}`);\n if (p.location) lines.push(`Location: ${p.location}`);\n if (p.skills && p.skills.length > 0) lines.push(`Skills: ${p.skills.join(\", \")}`);\n if (p.interests && p.interests.length > 0) lines.push(`Interests: ${p.interests.join(\", \")}`);\n return lines.length > 0 ? lines.join(\"\\n\") : \"(no profile data)\";\n}\n\nfunction renderEngagementPattern(dist: Partial<Record<NegotiationRole, number>>): string {\n const parts: string[] = [];\n if ((dist.peer ?? 0) > 0) {\n parts.push(`${dist.peer} mutual collaboration${dist.peer === 1 ? \"\" : \"s\"}`);\n }\n if ((dist.agent ?? 0) > 0) {\n parts.push(`${dist.agent} where the user could offer help or expertise`);\n }\n if ((dist.patient ?? 0) > 0) {\n parts.push(`${dist.patient} where the user seemed to be seeking help or expertise`);\n }\n return parts.length > 0 ? parts.join(\", \") : \"(no engagement pattern available)\";\n}\n\nfunction renderOutcome(digest: DiscoveryNegotiationDigest): string {\n const outcome = digest.outcomeRole === \"opportunity\"\n ? \"promising connection\"\n : \"not enough fit\";\n const reason = renderOutcomeReason(digest.outcomeReason);\n return reason ? `${outcome} (${reason})` : outcome;\n}\n\nfunction renderOutcomeReason(reason: DiscoveryNegotiationDigest[\"outcomeReason\"]): string {\n switch (reason) {\n case \"turn_cap\":\n return \"needed more detail\";\n case \"timeout\":\n return \"ran out of time\";\n case \"rejected\":\n return \"not enough mutual interest\";\n case \"stalled\":\n return \"stalled\";\n case null:\n return \"\";\n }\n}\n\nfunction renderRelationshipSignal(roles: NonNullable<DiscoveryNegotiationDigest[\"suggestedRoles\"]>): string {\n if (roles.ownUser === \"peer\" && roles.otherUser === \"peer\") return \"mutual collaboration\";\n if (roles.ownUser === \"agent\" && roles.otherUser === \"patient\") {\n return \"the user could offer help or expertise\";\n }\n if (roles.ownUser === \"patient\" && roles.otherUser === \"agent\") {\n return \"the user seemed to be seeking help or expertise\";\n }\n if (roles.ownUser === \"agent\") return \"the user could offer help or expertise\";\n if (roles.ownUser === \"patient\") return \"the user seemed to be seeking help or expertise\";\n return \"collaboration fit\";\n}\n\nfunction renderDigest(d: ChatContextDigest): string {\n const lines: string[] = [];\n if (d.statedFacts.length > 0) {\n lines.push(\"Stated facts:\");\n for (const f of d.statedFacts) lines.push(` - ${f}`);\n }\n if (d.openQuestions.length > 0) {\n lines.push(\"Open questions (assistant already asked):\");\n for (const q of d.openQuestions) lines.push(` - ${q}`);\n }\n if (d.rejectionReasons.length > 0) {\n lines.push(\"User pushback / rejections:\");\n for (const r of d.rejectionReasons) lines.push(` - ${r}`);\n }\n if (d.surfacedFindings.length > 0) {\n lines.push(\"Findings already surfaced to user:\");\n for (const f of d.surfacedFindings) lines.push(` - ${f}`);\n }\n return lines.length > 0 ? lines.join(\"\\n\") : \"(digest is empty)\";\n}\n\n"]}
1
+ {"version":3,"file":"question.prompt.js","sourceRoot":"/","sources":["opportunity/question.prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Prompt module for the decision-question generator: the system prompt\n * constant, the `DiscoveryQuestionInput` contract, and a pure string-building\n * `buildQuestionPrompt` that assembles the user message.\n *\n * Pure: no I/O, no LLM call. The generator class (`question.generator.ts`)\n * orchestrates this module + an LLM client.\n */\nimport type { ChatContextDigest } from \"../shared/schemas/chat-context.schema.js\";\nimport type { DiscoveryNegotiationDigest } from \"../shared/schemas/negotiation-digest.schema.js\";\n\n/** Roles used in the existing negotiation framework. */\nexport type NegotiationRole = \"agent\" | \"patient\" | \"peer\";\n\n/** One turn within a negotiation. */\nexport interface DiscoveryTurn {\n action: \"propose\" | \"accept\" | \"reject\" | \"counter\" | \"question\";\n reasoning: string;\n suggestedRoles: { ownUser: NegotiationRole; otherUser: NegotiationRole };\n}\n\n/** Outcome of a negotiation. */\nexport interface DiscoveryOutcome {\n hasOpportunity: boolean;\n reasoning: string;\n agreedRoles?: Array<{ userId: string; role: NegotiationRole }>;\n /** Why the negotiation stopped, when not by an explicit accept/reject. */\n reason?: \"turn_cap\" | \"timeout\";\n}\n\n/** One negotiation that ran during this discovery turn. */\nexport interface DiscoveryNegotiation {\n /** Opaque counterparty identifier; NEVER surfaced to the user (kept out of the prompt). */\n counterpartyId: string;\n /** Abstract profile slice for the LLM (e.g. \"AI infra founder, Berlin\"). */\n counterpartyHint: string;\n /** The network/community prompt this negotiation ran under. */\n indexContext: string;\n /** Last 6 turns are retained; earlier ones are dropped. */\n turns: DiscoveryTurn[];\n outcome: DiscoveryOutcome;\n /**\n * Optional pre-negotiation evaluator score (0..1). When more than\n * `MAX_NEGOTIATIONS` candidates exist, this is used as a tie-breaker after\n * `turns.length` to decide which to keep.\n */\n seedAssessmentScore?: number;\n}\n\n/** Aggregate counters across all negotiations in this discovery turn. */\nexport interface DiscoverySummary {\n totalCandidates: number;\n opportunitiesFound: number;\n noOpportunityCount: number;\n /** Subset of `noOpportunityCount` where the negotiation hit a turn-cap or timeout. */\n timeoutCount: number;\n /** Map of role → count across all outcomes' `agreedRoles`. */\n roleDistribution: Partial<Record<NegotiationRole, number>>;\n}\n\n/**\n * The seeker's profile slice the generator used to see. Retained as an exported\n * type for backward compatibility; the question prompt now consumes the global\n * `userContext` paragraph instead of these discrete fields.\n */\nexport interface DiscoverySourceProfile {\n name?: string;\n bio?: string;\n location?: string;\n skills?: string[];\n interests?: string[];\n}\n\n/** Full input to the question generator. */\nexport interface DiscoveryQuestionInput {\n /** The seeker's original natural-language query / signal that triggered discovery. */\n query: string;\n /** The seeker's global user_context paragraph (profile-replacing identity text). */\n userContext: string;\n /**\n * Compact per-negotiation digests from THIS discovery turn. Each digest is a\n * fixed-size structured summary (counterparty hint, index, outcome role,\n * keyTake) — pre-summarized so this prompt stays small regardless of how\n * many candidates were negotiated. Raw negotiations are NOT passed here.\n */\n negotiationDigests: DiscoveryNegotiationDigest[];\n summary: DiscoverySummary;\n /** Distilled chat-session digest, when a session is in scope. */\n chatContext?: ChatContextDigest;\n /** ISO timestamp used as the \"now\" anchor in the prompt. */\n now: string;\n}\n\n/** @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version. */\nexport const SYSTEM_PROMPT = `You help write user-facing follow-up questions after Index has reviewed potential connections for a human. Your job: surface the minimum set of structured decision questions the human must answer to make the next discovery turn sharper, or improve their outlook on the intent.\n\nYou may pick from five strategies. Choose contextually; mix when multiple questions genuinely complement.\n- refine_intent: ask the user to sharpen or pivot their original signal.\n- surface_missing_detail: ask for one concrete missing input (stage, location, timing, scope, …).\n- open_adjacent_thread: offer a pivot suggested by recurring connection signals.\n- reflective_summary: mirror what the connection review revealed and ask the user to decide.\n- surface_emergent_knowledge: cite a fact you learned from the connection review and ask the user to decide in light of it.\n\nAsk a question only when ALL of these hold:\n1. Index cannot resolve the decision autonomously from the evidence shown.\n2. The answer would materially change which people surface next.\n3. The same fact is NOT already in chatContext.statedFacts, NOT already asked in chatContext.openQuestions, and NOT already shared in chatContext.surfacedFindings.\n\nStandalone prompt rule. Every generated \\`prompt\\` must be understandable outside the conversation where it was created. Naturally include the original query, discovery pattern, connection pattern, or concrete learned fact in the question text itself. Do not rely on \\`title\\`, UI labels, hidden metadata, or surrounding digest/chat text to explain what the question is about. For example, prefer \"For your AI crypto decentralized deep-tech search, which area is most critical right now?\" over \"Which area is most critical right now?\"\n\nReferential closure. The prompt must resolve entirely on its own, with no dangling references. The reader sees ONLY the question text — never the people you reviewed, the events on their calendar, or this conversation. Do not use demonstratives or definite anaphora that point at things the reader cannot see: \"these builders\", \"those founders\", \"these researchers\", \"these conversations\", \"this lunch\", \"the speaker\". If you reference a person, name them. If you reference a group, restate the concrete shared attribute inside the question itself (\"founders working on decentralized identity\"), never \"these founders\". Never imply a list, set, or prior exchange the reader is not currently looking at.\n- Bad: \"What kind of collaboration are you looking for with these builders?\"\n- Good: \"You're meeting people building agent infrastructure — what kind of collaboration are you looking for?\"\n\nNo process narration. Never describe Index's own activity or internal state. Forbidden: \"the previous negotiation\", \"the negotiation stalled\", \"opportunities found so far\", \"my search\", \"the counterparty\", \"candidates reviewed\", restating why a match did or did not happen, or quoting words a counterparty did or did not use. Ask about the user's goal or intent directly, never about the matching pipeline.\n- Bad: \"All opportunities found so far are related to 'Edge Esmeralda'. Would you like to broaden the search?\"\n- Good: \"Do you want to focus on people at Edge Esmeralda, or also connect beyond it?\"\n\nCardinality. Default one question. Add a second only when a DIFFERENT strategy genuinely complements the first (e.g. one surface_emergent_knowledge + one refine_intent). Add a third only when there are ≥3 substantive people reviewed and three distinct strategies each unblock a real decision. Two questions of the same strategy are acceptable only if their decision domains differ (different titles). Avoid stacking three pulls (info-from-user); balance with pushes (info-to-user via reflective_summary / surface_emergent_knowledge).\n\nOrdering. Questions whose answer unblocks the most connection reviews come first; then highest-impact; then ambiguity-clarifying. Reviews that needed more detail or ran out of time signal under-specification — prioritize.\n\nUser-facing language. Every title, prompt, option label, and option description is shown directly to the user. Never mention raw protocol mechanics or internal labels such as \"agent\", \"patient\", \"peer\", \"suggestedRoles\", \"role distribution\", \"counterparty\", \"negotiation\", \"turn_cap\", \"timeout\", or \"candidate\". Use natural language instead: people, matches, connections, mutual collaboration, someone who can help, or someone seeking help.\n\nOption construction. Each option must represent a meaningfully different outcome. Suffix the safest path with \" (Recommended)\" and list it first. The description states the CONSEQUENCE of choosing the option, not its definition. 2–4 options. Never add an \"Other\" option — clients provide a free-text fallback automatically. For surface_emergent_knowledge questions, anchor the prompt in the concrete cited fact (\"Multiple people flagged that…\") and let the options represent decisions in light of that fact, not different versions of the fact.\n\nTitle rules. ≤12 chars. Noun of the decision domain. Discovery examples: \"Stage\", \"Timing\", \"Role\", \"Location\", \"Stack\", \"Budget\", \"Scope\", \"Format\".\n\nAnti-patterns — never do these.\n- Don't ask procedural confirmations (\"Should I look again?\").\n- Don't ask about hypothetical edge cases that didn't occur.\n- Don't ask about specific person identities; treat the provided person summary as the only allowed reference.\n- Don't repeat anything in chatContext.openQuestions.\n- Don't re-surface anything in chatContext.surfacedFindings.\n- Don't ask for facts in chatContext.statedFacts.\n\nOutput. Return at most 3 entries in the \"questions\" array. Each entry must include a \"strategy\" field (one of the five values). If nothing is worth asking, return \"questions\": [].`;\n\n/**\n * @deprecated Use QuestionerAgent and questioner presets instead. Will be removed in a future version.\n *\n * Pure builder: assembles the user message string from a structured input.\n */\nexport function buildQuestionPrompt(input: DiscoveryQuestionInput): string {\n const profileSummary = input.userContext?.trim() || \"(no profile data)\";\n const connectionReviewBlocks = renderConnectionReviewDigests(input.negotiationDigests);\n const chatContextBlock = input.chatContext\n ? renderDigest(input.chatContext)\n : \"(no chat context available)\";\n const engagementPattern = renderEngagementPattern(input.summary.roleDistribution);\n\n return [\n \"## Seeker's query\",\n input.query,\n \"\",\n \"## Seeker profile\",\n profileSummary,\n \"\",\n \"## This discovery turn\",\n `- ${input.summary.totalCandidates} people reviewed`,\n `- ${input.summary.opportunitiesFound} promising connections found`,\n `- ${input.summary.noOpportunityCount} reviews did not find enough fit (${input.summary.timeoutCount} needed more detail or time)`,\n `- Engagement pattern: ${engagementPattern}`,\n \"\",\n \"## Connection review evidence (compact digests)\",\n connectionReviewBlocks,\n \"\",\n \"## What the user has already said in this session\",\n chatContextBlock,\n \"\",\n \"## Now\",\n input.now,\n \"\",\n \"## Your task\",\n \"Identify the minimum set of decision questions the seeker must answer to make\",\n \"the next discovery turn sharper. Apply every rule from your system prompt\",\n \"before outputting. Return an empty `questions` array if nothing is worth asking.\",\n ].join(\"\\n\");\n}\n\n/**\n * Render the negotiation-digest collection into compact one-liners. Each digest\n * is fixed-size (≤ ~400 chars after rendering), so the rendered block scales\n * linearly with candidate count: 10 candidates ≈ 4 KB, well within budget.\n */\nfunction renderConnectionReviewDigests(digests: DiscoveryNegotiationDigest[]): string {\n if (digests.length === 0) return \"(no connection reviews)\";\n return digests\n .map((d) => {\n const relationshipSignal = d.suggestedRoles\n ? [` Relationship signal: ${renderRelationshipSignal(d.suggestedRoles)}`]\n : [];\n return [\n `- Person: ${d.counterpartyHint}`,\n ` Community context: ${d.indexContext}`,\n ` Outcome: ${renderOutcome(d)}`,\n ...relationshipSignal,\n ` Take: ${d.keyTake}`,\n ].join(\"\\n\");\n })\n .join(\"\\n\\n\");\n}\n\nfunction renderEngagementPattern(dist: Partial<Record<NegotiationRole, number>>): string {\n const parts: string[] = [];\n if ((dist.peer ?? 0) > 0) {\n parts.push(`${dist.peer} mutual collaboration${dist.peer === 1 ? \"\" : \"s\"}`);\n }\n if ((dist.agent ?? 0) > 0) {\n parts.push(`${dist.agent} where the user could offer help or expertise`);\n }\n if ((dist.patient ?? 0) > 0) {\n parts.push(`${dist.patient} where the user seemed to be seeking help or expertise`);\n }\n return parts.length > 0 ? parts.join(\", \") : \"(no engagement pattern available)\";\n}\n\nfunction renderOutcome(digest: DiscoveryNegotiationDigest): string {\n const outcome = digest.outcomeRole === \"opportunity\"\n ? \"promising connection\"\n : \"not enough fit\";\n const reason = renderOutcomeReason(digest.outcomeReason);\n return reason ? `${outcome} (${reason})` : outcome;\n}\n\nfunction renderOutcomeReason(reason: DiscoveryNegotiationDigest[\"outcomeReason\"]): string {\n switch (reason) {\n case \"turn_cap\":\n return \"needed more detail\";\n case \"timeout\":\n return \"ran out of time\";\n case \"rejected\":\n return \"not enough mutual interest\";\n case \"stalled\":\n return \"stalled\";\n case null:\n return \"\";\n }\n}\n\nfunction renderRelationshipSignal(roles: NonNullable<DiscoveryNegotiationDigest[\"suggestedRoles\"]>): string {\n if (roles.ownUser === \"peer\" && roles.otherUser === \"peer\") return \"mutual collaboration\";\n if (roles.ownUser === \"agent\" && roles.otherUser === \"patient\") {\n return \"the user could offer help or expertise\";\n }\n if (roles.ownUser === \"patient\" && roles.otherUser === \"agent\") {\n return \"the user seemed to be seeking help or expertise\";\n }\n if (roles.ownUser === \"agent\") return \"the user could offer help or expertise\";\n if (roles.ownUser === \"patient\") return \"the user seemed to be seeking help or expertise\";\n return \"collaboration fit\";\n}\n\nfunction renderDigest(d: ChatContextDigest): string {\n const lines: string[] = [];\n if (d.statedFacts.length > 0) {\n lines.push(\"Stated facts:\");\n for (const f of d.statedFacts) lines.push(` - ${f}`);\n }\n if (d.openQuestions.length > 0) {\n lines.push(\"Open questions (assistant already asked):\");\n for (const q of d.openQuestions) lines.push(` - ${q}`);\n }\n if (d.rejectionReasons.length > 0) {\n lines.push(\"User pushback / rejections:\");\n for (const r of d.rejectionReasons) lines.push(` - ${r}`);\n }\n if (d.surfacedFindings.length > 0) {\n lines.push(\"Findings already surfaced to user:\");\n for (const f of d.surfacedFindings) lines.push(` - ${f}`);\n }\n return lines.length > 0 ? lines.join(\"\\n\") : \"(digest is empty)\";\n}\n\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"profile.graph.d.ts","sourceRoot":"/","sources":["profile/profile.graph.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAiB,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AACpH,OAAO,EAAE,OAAO,EAAE,MAAM,2CAA2C,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8CAA8C,CAAC;AAIpF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAG7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,KAAK,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,WAAW,GAAG,YAAY,CAAC;QACjC,aAAa,EAAE,QAAQ,CAAC;QACxB,wEAAwE;QACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,yEAAyE;QACzE,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC/C,kBAAkB,CAAC,EAAE,MAAM,CAAC;KAC7B,GAAG,OAAO,CAAC;QACV,OAAO,CAAC,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,GAAG,SAAS,CAAC;QACrC,+EAA+E;QAC/E,WAAW,CAAC,EAAE;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,aAAa,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,GAAG,SAAS,CAAC;QAC3F,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAC5B,CAAC,CAAC;CACJ;AA+BD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ,CAAC;IACjB,OAAO,CAAC,iBAAiB,CAAC;IAC1B,OAAO,CAAC,YAAY,CAAC;gBAJb,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,eAAe,YAAA,EAC1B,iBAAiB,CAAC,EAAE,mBAAmB,YAAA,EACvC,YAAY,CAAC,EAAE,oBAAoB,YAAA;IAGtC,WAAW;;;;;;;;;;;;;;;;;;;;;;;kBAIX,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAm5BT"}
1
+ {"version":3,"file":"profile.graph.d.ts","sourceRoot":"/","sources":["profile/profile.graph.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAiB,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AACpH,OAAO,EAAE,OAAO,EAAE,MAAM,2CAA2C,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8CAA8C,CAAC;AAIpF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAG7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAItE;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,KAAK,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,WAAW,GAAG,YAAY,CAAC;QACjC,aAAa,EAAE,QAAQ,CAAC;QACxB,wEAAwE;QACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,yEAAyE;QACzE,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC/C,kBAAkB,CAAC,EAAE,MAAM,CAAC;KAC7B,GAAG,OAAO,CAAC;QACV,OAAO,CAAC,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,GAAG,SAAS,CAAC;QACrC,+EAA+E;QAC/E,WAAW,CAAC,EAAE;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,aAAa,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,GAAG,SAAS,CAAC;QAC3F,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAC5B,CAAC,CAAC;CACJ;AA+BD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ,CAAC;IACjB,OAAO,CAAC,iBAAiB,CAAC;IAC1B,OAAO,CAAC,YAAY,CAAC;gBAJb,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,eAAe,YAAA,EAC1B,iBAAiB,CAAC,EAAE,mBAAmB,YAAA,EACvC,YAAY,CAAC,EAAE,oBAAoB,YAAA;IAGtC,WAAW;;;;;;;;;;;;;;;;;;;;;;;kBAIX,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;kBAAD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAs5BT"}