@indexnetwork/protocol 4.0.0-rc.289.1 → 4.1.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.
- package/dist/chat/chat.prompt.js +21 -21
- package/dist/chat/chat.prompt.js.map +1 -1
- package/dist/chat/chat.prompt.modules.js +8 -8
- package/dist/chat/chat.prompt.modules.js.map +1 -1
- package/dist/contact/contact.tools.js +3 -3
- package/dist/contact/contact.tools.js.map +1 -1
- package/dist/enrichment/enrichment.graph.js +1 -1
- package/dist/enrichment/enrichment.graph.js.map +1 -1
- package/dist/enrichment/enrichment.tools.js +47 -47
- package/dist/enrichment/enrichment.tools.js.map +1 -1
- package/dist/intent/intent.graph.d.ts.map +1 -1
- package/dist/intent/intent.graph.js +7 -6
- package/dist/intent/intent.graph.js.map +1 -1
- package/dist/intent/intent.tools.js +2 -2
- package/dist/intent/intent.tools.js.map +1 -1
- package/dist/mcp/mcp.server.d.ts +1 -1
- package/dist/mcp/mcp.server.d.ts.map +1 -1
- package/dist/mcp/mcp.server.js +12 -4
- package/dist/mcp/mcp.server.js.map +1 -1
- package/dist/negotiation/negotiation.tools.js +1 -1
- package/dist/negotiation/negotiation.tools.js.map +1 -1
- package/dist/network/network.tools.js +2 -2
- package/dist/network/network.tools.js.map +1 -1
- package/dist/opportunity/opportunity.graph.d.ts +8 -8
- package/dist/opportunity/opportunity.graph.js +7 -7
- package/dist/opportunity/opportunity.graph.js.map +1 -1
- package/dist/opportunity/opportunity.state.d.ts +2 -2
- package/dist/opportunity/opportunity.state.d.ts.map +1 -1
- package/dist/opportunity/opportunity.state.js +1 -1
- package/dist/opportunity/opportunity.state.js.map +1 -1
- package/dist/opportunity/opportunity.tools.js +8 -8
- package/dist/opportunity/opportunity.tools.js.map +1 -1
- package/dist/shared/agent/tool.registry.d.ts.map +1 -1
- package/dist/shared/agent/tool.registry.js +26 -0
- package/dist/shared/agent/tool.registry.js.map +1 -1
- package/dist/shared/agent/tool.runtime.d.ts.map +1 -1
- package/dist/shared/agent/tool.runtime.js +6 -0
- package/dist/shared/agent/tool.runtime.js.map +1 -1
- package/dist/shared/agent/utility.tools.js +5 -5
- package/dist/shared/agent/utility.tools.js.map +1 -1
- package/dist/shared/interfaces/database.interface.d.ts +2 -2
- package/dist/shared/interfaces/database.interface.js.map +1 -1
- package/dist/shared/interfaces/enrichment-run.interface.d.ts +1 -1
- package/dist/shared/interfaces/enrichment-run.interface.d.ts.map +1 -1
- package/dist/shared/interfaces/enrichment-run.interface.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contact.tools.js","sourceRoot":"/","sources":["contact/contact.tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAE5E,MAAM,MAAM,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;AAE9C;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAsB,EAAE,IAAc;IACvE,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IAChC,6EAA6E;IAC7E,+EAA+E;IAC/E,yEAAyE;IACzE,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,KAAK,IAAI,CAAC;IAEtD,6EAA6E;IAC7E,8EAA8E;IAC9E,MAAM,eAAe,GAAG,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC;QACnD,IAAI,EAAE,iBAAiB;QACvB,WAAW,EACT,+HAA+H;YAC/H,gGAAgG;YAChG,yHAAyH;YACzH,4HAA4H;YAC5H,0FAA0F;YAC1F,8HAA8H;YAC9H,gEAAgE;YAChE,oHAAoH;YACpH,4FAA4F;QAC9F,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;gBACzB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;gBACzE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2EAA2E,CAAC;aACxG,CAAC,CAAC,CAAC,QAAQ,CAAC,uGAAuG,CAAC;SACtH,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;YACpC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,cAAc,CAChD,OAAO,CAAC,MAAM,EACd,KAAK,CAAC,QAAQ,CACf,CAAC;gBACF,OAAO,OAAO,CAAC;oBACb,OAAO,EAAE,YAAY,MAAM,CAAC,QAAQ,4BAA4B;oBAChE,QAAQ,EAAE,MAAM,CAAC,QAAQ;oBACzB,OAAO,EAAE,MAAM,CAAC,OAAO;oBACvB,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;iBAC1C,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;gBACnD,OAAO,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;KACF,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEV,MAAM,aAAa,GAAG,UAAU,CAAC;QAC/B,IAAI,EAAE,eAAe;QACrB,WAAW,EACT,0GAA0G;YAC1G,6GAA6G;YAC7G,qGAAqG;YACrG,yDAAyD;YACzD,6GAA6G;YAC7G,mGAAmG;YACnG,kIAAkI;QACpI,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gHAAgH,CAAC;SACxJ,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;YACpC,IAAI,CAAC;gBACH,IAAI,QAAQ,GAAG,MAAM,cAAc,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBAEjE,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;oBACnC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC5C,CAAC;gBAED,OAAO,OAAO,CAAC;oBACb,KAAK,EAAE,QAAQ,CAAC,MAAM;oBACtB,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;wBAC3B,MAAM,EAAE,CAAC,CAAC,MAAM;wBAChB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;wBACjB,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK;wBACnB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM;wBACrB,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO;qBACxB,CAAC,CAAC;iBACJ,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;gBACjD,OAAO,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC;QAC/C,IAAI,EAAE,aAAa;QACnB,WAAW,EACT,uFAAuF;YACvF,oDAAoD;YACpD,4FAA4F;YAC5F,8FAA8F;YAC9F,4FAA4F;YAC5F,gHAAgH;YAChH,6GAA6G;YAC7G,4FAA4F;QAC9F,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oHAAoH,CAAC;YAChJ,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sIAAsI,CAAC;SAC7K,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;YACpC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBAEjH,OAAO,OAAO,CAAC;oBACb,KAAK,EAAE,IAAI;oBACX,OAAO,EAAE,MAAM,CAAC,KAAK;wBACnB,CAAC,CAAC,SAAS,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,oDAAoD;wBACxF,CAAC,CAAC,SAAS,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,mBAAmB;oBACzD,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,UAAU,EAAE,MAAM,CAAC,KAAK;iBACzB,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;gBAC/C,OAAO,KAAK,CAAC,0CAA0C,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;KACF,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEV,MAAM,cAAc,GAAG,UAAU,CAAC;QAChC,IAAI,EAAE,gBAAgB;QACtB,WAAW,EACT,0GAA0G;YAC1G,wHAAwH;YACxH,sHAAsH;YACtH,qGAAqG;YACrG,gFAAgF;YAChF,yDAAyD;QAC3D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2EAA2E,CAAC;SAChH,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;YACpC,IAAI,CAAC;gBACH,MAAM,cAAc,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;gBACxE,OAAO,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC,CAAC;YACnF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;gBAClD,OAAO,KAAK,CAAC,6CAA6C,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,UAAU,CAAC;QACjC,IAAI,EAAE,iBAAiB;QACvB,WAAW,EACT,oGAAoG;YACpG,4GAA4G;YAC5G,wDAAwD;YACxD,yHAAyH;YACzH,gFAAgF;QAClF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,uFAAuF,CAAC;YACjI,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;SAC3G,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;YACpC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBACjG,OAAO,OAAO,CAAC;oBACb,KAAK,EAAE,IAAI,CAAC,MAAM;oBAClB,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;wBACvB,MAAM,EAAE,CAAC,CAAC,SAAS;wBACnB,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,KAAK,EAAE,CAAC,CAAC,KAAK;wBACd,MAAM,EAAE,CAAC,CAAC,MAAM;wBAChB,OAAO,EAAE,CAAC,CAAC,OAAO;qBACnB,CAAC,CAAC;iBACJ,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;gBACnD,OAAO,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,aAAa;QACb,cAAc;QACd,eAAe;KAChB,CAAC;AACJ,CAAC","sourcesContent":["import { z } from 'zod';\nimport type { DefineTool, ToolDeps } from '../shared/agent/tool.helpers.js';\nimport { success, error } from '../shared/agent/tool.helpers.js';\nimport { protocolLogger } from '../shared/observability/protocol.logger.js';\n\nconst logger = protocolLogger('ContactTools');\n\n/**\n * Creates contact management tools for the chat agent.\n * Enables importing, listing, and managing the user's network.\n */\nexport function createContactTools(defineTool: DefineTool, deps: ToolDeps) {\n const { contactService } = deps;\n // Contact import / manual-add create ghost users. These are gated behind the\n // CONTACTS_ENABLED flag (injected as deps.contactsEnabled). Read/remove/search\n // tools below are always available so existing contacts stay manageable.\n const contactsEnabled = deps.contactsEnabled === true;\n\n // Only register when enabled: in the registry path defineTool registers as a\n // side effect, so the call itself must be gated, not just the returned array.\n const import_contacts = contactsEnabled ? defineTool({\n name: 'import_contacts',\n description:\n \"Bulk-imports contacts into the authenticated user's personal network (personal index). Contacts become members of the user's \" +\n \"personal index with 'contact' permission, making them available for opportunity discovery.\\n\\n\" +\n \"**What happens:** Each contact is matched by email. If the email belongs to an existing user, they're linked directly. \" +\n \"If not, a 'ghost user' is created — a placeholder account enriched with public profile data (from LinkedIn, GitHub, etc.) \" +\n \"that participates in opportunity matching even before the person joins the platform.\\n\\n\" +\n \"**When to use:** When the user provides a list of contacts to add (from CSV, manual input, or any source other than Gmail). \" +\n \"For Gmail specifically, use import_gmail_contacts instead.\\n\\n\" +\n \"**Returns:** Import statistics: imported (total processed), skipped (invalid), newContacts (ghost users created), \" +\n \"existingContacts (already in network). Use list_contacts to see all contacts after import.\",\n querySchema: z.object({\n contacts: z.array(z.object({\n name: z.string().describe('Full name of the contact (e.g. \"Jane Smith\")'),\n email: z.string().describe('Email address — used as the unique identifier for matching existing users'),\n })).describe('Array of contact objects to import. Each must have name and email. Duplicates (by email) are skipped.'),\n }),\n handler: async ({ context, query }) => {\n try {\n const result = await contactService.importContacts(\n context.userId,\n query.contacts\n );\n return success({\n message: `Imported ${result.imported} contacts to your network.`,\n imported: result.imported,\n skipped: result.skipped,\n newContacts: result.newContacts,\n existingContacts: result.existingContacts,\n });\n } catch (err) {\n logger.error('Failed to import contacts', { err });\n return error('Failed to import contacts. Please try again.');\n }\n },\n }) : null;\n\n const list_contacts = defineTool({\n name: 'list_contacts',\n description:\n \"Lists all contacts in the authenticated user's personal network. Contacts are people the user has added \" +\n \"(via import_contacts, add_contact, or import_gmail_contacts) stored as members of their personal index.\\n\\n\" +\n \"**When to use:** To see who's in the user's network, find a contact's userId for other operations, \" +\n \"or check if a specific person is already a contact.\\n\\n\" +\n \"**Returns:** Array of contacts, each with: userId (use with read_user_profiles or discover_opportunities), \" +\n \"name, email, avatar URL, and isGhost (true = no account yet, profile enriched from public data). \" +\n \"Use the userId with read_user_profiles(userId) to get the full profile, or with discover_opportunities(targetUserId) to connect.\",\n querySchema: z.object({\n limit: z.number().optional().describe('Maximum number of contacts to return. Omit to return all contacts. Use for large networks to paginate results.'),\n }),\n handler: async ({ context, query }) => {\n try {\n let contacts = await contactService.listContacts(context.userId);\n\n if (query.limit && query.limit > 0) {\n contacts = contacts.slice(0, query.limit);\n }\n\n return success({\n count: contacts.length,\n contacts: contacts.map(c => ({\n userId: c.userId,\n name: c.user.name,\n email: c.user.email,\n avatar: c.user.avatar,\n isGhost: c.user.isGhost,\n })),\n });\n } catch (err) {\n logger.error('Failed to list contacts', { err });\n return error('Failed to list contacts. Please try again.');\n }\n },\n });\n\n const add_contact = contactsEnabled ? defineTool({\n name: 'add_contact',\n description:\n \"Adds a single contact to the authenticated user's personal network by email address. \" +\n \"For bulk imports, use import_contacts instead.\\n\\n\" +\n \"**What happens:** Looks up the email. If an account exists, links that user as a contact. \" +\n \"If not, creates a ghost user (placeholder enriched with public profile data) and adds them. \" +\n \"The contact can then appear in opportunity discovery within the user's personal index.\\n\\n\" +\n \"**When to use:** When the user wants to add a specific person (e.g. 'add john@example.com to my network').\\n\\n\" +\n \"**Returns:** Confirmation with the contact's userId and whether a new ghost user was created (isNewGhost). \" +\n \"Use the userId with discover_opportunities(targetUserId) to find connection opportunities.\",\n querySchema: z.object({\n email: z.string().describe('Email address of the person to add. Used as unique identifier — if already a contact, the operation is idempotent.'),\n name: z.string().optional().describe('Full name of the contact. Optional — if omitted, the email prefix is used as name. Provide when known for better profile enrichment.'),\n }),\n handler: async ({ context, query }) => {\n try {\n const result = await contactService.addContact(context.userId, query.email, { name: query.name, restore: true });\n\n return success({\n added: true,\n message: result.isNew\n ? `Added ${query.name || query.email} to your network. Their profile is being enriched.`\n : `Added ${query.name || query.email} to your network.`,\n userId: result.userId,\n isNewGhost: result.isNew,\n });\n } catch (err) {\n logger.error('Failed to add contact', { err });\n return error('Failed to add contact. Please try again.');\n }\n },\n }) : null;\n\n const remove_contact = defineTool({\n name: 'remove_contact',\n description:\n \"Removes a contact from the authenticated user's personal network. The contact relationship is deleted — \" +\n \"the person is no longer a member of the user's personal index and won't appear in personal-index-scoped discovery.\\n\\n\" +\n \"**When to use:** When the user wants to remove someone from their network (e.g. 'remove John from my contacts').\\n\\n\" +\n \"**Note:** This only removes the contact relationship. If the contact is a real user (not a ghost), \" +\n \"they still exist on the platform and may appear in shared index discovery.\\n\\n\" +\n \"**Returns:** Confirmation that the contact was removed.\",\n querySchema: z.object({\n contactUserId: z.string().describe('The userId of the contact to remove. Get this from list_contacts results.'),\n }),\n handler: async ({ context, query }) => {\n try {\n await contactService.removeContact(context.userId, query.contactUserId);\n return success({ removed: true, message: 'Contact removed from your network.' });\n } catch (err) {\n logger.error('Failed to remove contact', { err });\n return error('Failed to remove contact. Please try again.');\n }\n },\n });\n\n const search_contacts = defineTool({\n name: 'search_contacts',\n description:\n \"Searches the authenticated user's personal network by name or email (case-insensitive substring). \" +\n \"Use when the user refers to a contact by partial name or email and you need their userId for another tool \" +\n \"(e.g. read_user_profiles, discover_opportunities).\\n\\n\" +\n \"**When to use:** Before list_contacts when the network is large — returns only matching contacts, bounded by limit.\\n\\n\" +\n \"**Returns:** Array of matching contacts: userId, name, email, avatar, isGhost.\",\n querySchema: z.object({\n query: z.string().trim().min(1).describe('Free-text query matched against contact name and email (case-insensitive, substring).'),\n limit: z.number().int().positive().max(100).optional().describe('Maximum rows to return. Defaults to 25.'),\n }),\n handler: async ({ context, query }) => {\n try {\n const rows = await contactService.searchContacts(context.userId, query.query, query.limit ?? 25);\n return success({\n count: rows.length,\n contacts: rows.map(r => ({\n userId: r.contactId,\n name: r.name,\n email: r.email,\n avatar: r.avatar,\n isGhost: r.isGhost,\n })),\n });\n } catch (err) {\n logger.error('Failed to search contacts', { err });\n return error('Failed to search contacts. Please try again.');\n }\n },\n });\n\n return [\n ...(import_contacts ? [import_contacts] : []),\n ...(add_contact ? [add_contact] : []),\n list_contacts,\n remove_contact,\n search_contacts,\n ];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"contact.tools.js","sourceRoot":"/","sources":["contact/contact.tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport type { DefineTool, ToolDeps } from '../shared/agent/tool.helpers.js';\nimport { success, error } from '../shared/agent/tool.helpers.js';\nimport { protocolLogger } from '../shared/observability/protocol.logger.js';\n\nconst logger = protocolLogger('ContactTools');\n\n/**\n * Creates contact management tools for the chat agent.\n * Enables importing, listing, and managing the user's network.\n */\nexport function createContactTools(defineTool: DefineTool, deps: ToolDeps) {\n const { contactService } = deps;\n // Contact import / manual-add create ghost users. These are gated behind the\n // CONTACTS_ENABLED flag (injected as deps.contactsEnabled). Read/remove/search\n // tools below are always available so existing contacts stay manageable.\n const contactsEnabled = deps.contactsEnabled === true;\n\n // Only register when enabled: in the registry path defineTool registers as a\n // side effect, so the call itself must be gated, not just the returned array.\n const import_contacts = contactsEnabled ? defineTool({\n name: 'import_contacts',\n description:\n \"Bulk-imports contacts into the authenticated user's personal network (personal index). Contacts become members of the user's \" +\n \"personal index with 'contact' permission, making them available for opportunity discovery.\\n\\n\" +\n \"**What happens:** Each contact is matched by email. If the email belongs to an existing user, they're linked directly. \" +\n \"If not, a 'ghost user' is created — a placeholder account enriched with public profile data (from LinkedIn, GitHub, etc.) \" +\n \"that participates in opportunity matching even before the person joins the platform.\\n\\n\" +\n \"**When to use:** When the user provides a list of contacts to add (from CSV, manual input, or any source other than Gmail). \" +\n \"For Gmail specifically, use import_gmail_contacts instead.\\n\\n\" +\n \"**Returns:** Import statistics: imported (total processed), skipped (invalid), newContacts (ghost users created), \" +\n \"existingContacts (already in network). Use list_contacts to see all contacts after import.\",\n querySchema: z.object({\n contacts: z.array(z.object({\n name: z.string().describe('Full name of the contact (e.g. \"Jane Smith\")'),\n email: z.string().describe('Email address — used as the unique identifier for matching existing users'),\n })).describe('Array of contact objects to import. Each must have name and email. Duplicates (by email) are skipped.'),\n }),\n handler: async ({ context, query }) => {\n try {\n const result = await contactService.importContacts(\n context.userId,\n query.contacts\n );\n return success({\n message: `Imported ${result.imported} contacts to your network.`,\n imported: result.imported,\n skipped: result.skipped,\n newContacts: result.newContacts,\n existingContacts: result.existingContacts,\n });\n } catch (err) {\n logger.error('Failed to import contacts', { err });\n return error('Failed to import contacts. Please try again.');\n }\n },\n }) : null;\n\n const list_contacts = defineTool({\n name: 'list_contacts',\n description:\n \"Lists all contacts in the authenticated user's personal network. Contacts are people the user has added \" +\n \"(via import_contacts, add_contact, or import_gmail_contacts) stored as members of their personal index.\\n\\n\" +\n \"**When to use:** To see who's in the user's network, find a contact's userId for other operations, \" +\n \"or check if a specific person is already a contact.\\n\\n\" +\n \"**Returns:** Array of contacts, each with: userId (use with read_user_contexts or discover_opportunities), \" +\n \"name, email, avatar URL, and isGhost (true = no account yet, profile enriched from public data). \" +\n \"Use the userId with read_user_contexts(userId) to get the full profile, or with discover_opportunities(targetUserId) to connect.\",\n querySchema: z.object({\n limit: z.number().optional().describe('Maximum number of contacts to return. Omit to return all contacts. Use for large networks to paginate results.'),\n }),\n handler: async ({ context, query }) => {\n try {\n let contacts = await contactService.listContacts(context.userId);\n\n if (query.limit && query.limit > 0) {\n contacts = contacts.slice(0, query.limit);\n }\n\n return success({\n count: contacts.length,\n contacts: contacts.map(c => ({\n userId: c.userId,\n name: c.user.name,\n email: c.user.email,\n avatar: c.user.avatar,\n isGhost: c.user.isGhost,\n })),\n });\n } catch (err) {\n logger.error('Failed to list contacts', { err });\n return error('Failed to list contacts. Please try again.');\n }\n },\n });\n\n const add_contact = contactsEnabled ? defineTool({\n name: 'add_contact',\n description:\n \"Adds a single contact to the authenticated user's personal network by email address. \" +\n \"For bulk imports, use import_contacts instead.\\n\\n\" +\n \"**What happens:** Looks up the email. If an account exists, links that user as a contact. \" +\n \"If not, creates a ghost user (placeholder enriched with public profile data) and adds them. \" +\n \"The contact can then appear in opportunity discovery within the user's personal index.\\n\\n\" +\n \"**When to use:** When the user wants to add a specific person (e.g. 'add john@example.com to my network').\\n\\n\" +\n \"**Returns:** Confirmation with the contact's userId and whether a new ghost user was created (isNewGhost). \" +\n \"Use the userId with discover_opportunities(targetUserId) to find connection opportunities.\",\n querySchema: z.object({\n email: z.string().describe('Email address of the person to add. Used as unique identifier — if already a contact, the operation is idempotent.'),\n name: z.string().optional().describe('Full name of the contact. Optional — if omitted, the email prefix is used as name. Provide when known for better profile enrichment.'),\n }),\n handler: async ({ context, query }) => {\n try {\n const result = await contactService.addContact(context.userId, query.email, { name: query.name, restore: true });\n\n return success({\n added: true,\n message: result.isNew\n ? `Added ${query.name || query.email} to your network. Their profile is being enriched.`\n : `Added ${query.name || query.email} to your network.`,\n userId: result.userId,\n isNewGhost: result.isNew,\n });\n } catch (err) {\n logger.error('Failed to add contact', { err });\n return error('Failed to add contact. Please try again.');\n }\n },\n }) : null;\n\n const remove_contact = defineTool({\n name: 'remove_contact',\n description:\n \"Removes a contact from the authenticated user's personal network. The contact relationship is deleted — \" +\n \"the person is no longer a member of the user's personal index and won't appear in personal-index-scoped discovery.\\n\\n\" +\n \"**When to use:** When the user wants to remove someone from their network (e.g. 'remove John from my contacts').\\n\\n\" +\n \"**Note:** This only removes the contact relationship. If the contact is a real user (not a ghost), \" +\n \"they still exist on the platform and may appear in shared index discovery.\\n\\n\" +\n \"**Returns:** Confirmation that the contact was removed.\",\n querySchema: z.object({\n contactUserId: z.string().describe('The userId of the contact to remove. Get this from list_contacts results.'),\n }),\n handler: async ({ context, query }) => {\n try {\n await contactService.removeContact(context.userId, query.contactUserId);\n return success({ removed: true, message: 'Contact removed from your network.' });\n } catch (err) {\n logger.error('Failed to remove contact', { err });\n return error('Failed to remove contact. Please try again.');\n }\n },\n });\n\n const search_contacts = defineTool({\n name: 'search_contacts',\n description:\n \"Searches the authenticated user's personal network by name or email (case-insensitive substring). \" +\n \"Use when the user refers to a contact by partial name or email and you need their userId for another tool \" +\n \"(e.g. read_user_contexts, discover_opportunities).\\n\\n\" +\n \"**When to use:** Before list_contacts when the network is large — returns only matching contacts, bounded by limit.\\n\\n\" +\n \"**Returns:** Array of matching contacts: userId, name, email, avatar, isGhost.\",\n querySchema: z.object({\n query: z.string().trim().min(1).describe('Free-text query matched against contact name and email (case-insensitive, substring).'),\n limit: z.number().int().positive().max(100).optional().describe('Maximum rows to return. Defaults to 25.'),\n }),\n handler: async ({ context, query }) => {\n try {\n const rows = await contactService.searchContacts(context.userId, query.query, query.limit ?? 25);\n return success({\n count: rows.length,\n contacts: rows.map(r => ({\n userId: r.contactId,\n name: r.name,\n email: r.email,\n avatar: r.avatar,\n isGhost: r.isGhost,\n })),\n });\n } catch (err) {\n logger.error('Failed to search contacts', { err });\n return error('Failed to search contacts. Please try again.');\n }\n },\n });\n\n return [\n ...(import_contacts ? [import_contacts] : []),\n ...(add_contact ? [add_contact] : []),\n list_contacts,\n remove_contact,\n search_contacts,\n ];\n}\n"]}
|
|
@@ -99,7 +99,7 @@ export class EnrichmentGraphFactory {
|
|
|
99
99
|
hasProfile: true,
|
|
100
100
|
// Thin identity only. The structured skills/interests attributes are
|
|
101
101
|
// retired (user_profiles removal, WS6); the rich identity text now
|
|
102
|
-
// comes from the global user_context, injected by
|
|
102
|
+
// comes from the global user_context, injected by read_user_contexts.
|
|
103
103
|
profile: {
|
|
104
104
|
id: profileWithId?.id,
|
|
105
105
|
name: profile?.identity?.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrichment.graph.js","sourceRoot":"/","sources":["enrichment/enrichment.graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAI7D,OAAO,EAAE,wCAAwC,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAC9G,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAE5E,OAAO,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAE5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AA0BxE,MAAM,MAAM,GAAG,cAAc,CAAC,wBAAwB,CAAC,CAAC;AAExD,iFAAiF;AACjF,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAEvC,kFAAkF;AAClF,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ;IACzE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa;IACvE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,mBAAmB;IACzE,gBAAgB,EAAE,gBAAgB,EAAE,kBAAkB;CACvD,CAAC,CAAC;AAEH;;;;GAIG;AACH,SAAS,wBAAwB,CAAC,KAAyB;IACzD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,MAAM,GAAG,2BAA2B;QAAE,OAAO,KAAK,CAAC;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACpC,IAAI,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAClD,IAAI,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACzE,OAAO,IAAI,CAAC;AACd,CAAC;AAGD;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,sBAAsB;IACjC,YACU,QAAiC,EACjC,OAAgB,EAChB,QAA0B,EAC1B,iBAAuC,EACvC,YAAmC;QAJnC,aAAQ,GAAR,QAAQ,CAAyB;QACjC,YAAO,GAAP,OAAO,CAAS;QAChB,aAAQ,GAAR,QAAQ,CAAkB;QAC1B,sBAAiB,GAAjB,iBAAiB,CAAsB;QACvC,iBAAY,GAAZ,YAAY,CAAuB;IACzC,CAAC;IAEE,WAAW;QAChB,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,EAAE,CAAC;QAElD,4DAA4D;QAC5D,oBAAoB;QACpB,oEAAoE;QACpE,oBAAoB;QACpB,+CAA+C;QAC/C,4DAA4D;QAC5D,MAAM,cAAc,GAAG,KAAK,EAAE,KAAwC,EAAE,EAAE;YACxE,OAAO,KAAK,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;gBACjD,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;oBAClB,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;oBAC/B,OAAO;wBACL,KAAK,EAAE,oBAAoB;qBAC5B,CAAC;gBACJ,CAAC;gBAED,MAAM,CAAC,OAAO,CAAC,2BAA2B,EAAE;oBAC1C,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,aAAa,EAAE,KAAK,CAAC,aAAa;oBAClC,WAAW,EAAE,KAAK,CAAC,WAAW;iBAC/B,CAAC,CAAC;gBAEH,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAQ,CAAC;oBACpE,4EAA4E;oBAC5E,4EAA4E;oBAC5E,2EAA2E;oBAC3E,2EAA2E;oBAC3E,MAAM,eAAe,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;oBAEpG,kDAAkD;oBAClD,IAAI,KAAK,CAAC,aAAa,KAAK,OAAO,EAAE,CAAC;wBACpC,MAAM,CAAC,OAAO,CAAC,wDAAwD,EAAE;4BACvE,UAAU,EAAE,eAAe;yBAC5B,CAAC,CAAC;wBACH,MAAM,aAAa,GAAG,eAAe,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;wBACpG,OAAO;4BACL,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;4BAC7D,UAAU,EAAE,eAAe;gCACzB,CAAC,CAAC;oCACE,UAAU,EAAE,IAAI;oCAChB,qEAAqE;oCACrE,mEAAmE;oCACnE,sEAAsE;oCACtE,OAAO,EAAE;wCACP,EAAE,EAAE,aAAa,EAAE,EAAE;wCACrB,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI;wCAC7B,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG;wCAC3B,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ;qCACtC;iCACF;gCACH,CAAC,CAAC;oCACE,UAAU,EAAE,KAAK;oCACjB,OAAO,EACL,wJAAwJ;iCAC3J;yBACN,CAAC;oBACJ,CAAC;oBAED,2CAA2C;oBAC3C,0FAA0F;oBAC1F,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,wBAAwB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBAClF,MAAM,sBAAsB,GAAG,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,kBAAkB,CAAC,CAAC;oBAE7F,0FAA0F;oBAC1F,MAAM,gBAAgB,GAAG,sBAAsB,IAAI,CAAC,kBAAkB,CAAC;oBAEvE,qEAAqE;oBACrE,IAAI,aAAa,GAAG,KAAK,CAAC;oBAC1B,MAAM,eAAe,GAAa,EAAE,CAAC;oBAErC,IAAI,gBAAgB,EAAE,CAAC;wBACrB,MAAM,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC;wBAEpE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;wBAEvD,IAAI,CAAC,IAAI,EAAE,CAAC;4BACV,MAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;4BACzD,OAAO;gCACL,KAAK,EAAE,mBAAmB,KAAK,CAAC,MAAM,EAAE;6BACzC,CAAC;wBACJ,CAAC;wBAED,qEAAqE;wBACrE,gDAAgD;wBAChD,oDAAoD;wBAEpD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;wBACjE,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;wBAEtC,yDAAyD;wBACzD,uDAAuD;wBACvD,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI;4BACjC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;4BACvB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;4BACxB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;wBAErD,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;wBAErE,6CAA6C;wBAC7C,sFAAsF;wBACtF,+DAA+D;wBAC/D,kDAAkD;wBAElD,MAAM,cAAc,GAAG,UAAU,IAAI,iBAAiB,CAAC;wBAEvD,IAAI,CAAC,cAAc,EAAE,CAAC;4BACpB,aAAa,GAAG,IAAI,CAAC;4BAErB,sDAAsD;4BACtD,IAAI,CAAC,UAAU,EAAE,CAAC;gCAChB,eAAe,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;4BACtC,CAAC;4BACD,IAAI,CAAC,iBAAiB,EAAE,CAAC;gCACvB,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;4BACpC,CAAC;4BACD,IAAI,CAAC,WAAW,EAAE,CAAC;gCACjB,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,eAAe;4BACnD,CAAC;4BAED,MAAM,CAAC,OAAO,CAAC,+CAA+C,EAAE;gCAC9D,UAAU;gCACV,iBAAiB;gCACjB,WAAW;gCACX,WAAW,EAAE,IAAI,CAAC,IAAI;gCACtB,eAAe;6BAChB,CAAC,CAAC;wBACL,CAAC;6BAAM,CAAC;4BACN,MAAM,CAAC,OAAO,CAAC,4CAA4C,EAAE;gCAC3D,UAAU;gCACV,iBAAiB;gCACjB,WAAW;gCACX,eAAe,EAAE,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW;6BAC3D,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;oBAED,MAAM,CAAC,OAAO,CAAC,6BAA6B,EAAE;wBAC5C,UAAU,EAAE,eAAe;wBAC3B,sBAAsB;wBACtB,aAAa;wBACb,eAAe;wBACf,WAAW,EAAE,KAAK,CAAC,WAAW;wBAC9B,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK;wBACvB,kBAAkB;qBACnB,CAAC,CAAC;oBAEH,OAAO;wBACL,6EAA6E;wBAC7E,6EAA6E;wBAC7E,sEAAsE;wBACtE,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;wBAC7D,sBAAsB;wBACtB,aAAa;wBACb,eAAe;qBAChB,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE;wBACrC,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;qBAC9D,CAAC,CAAC;oBACH,OAAO;wBACL,OAAO,EAAE,SAAS;wBAClB,KAAK,EAAE,yCAAyC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;qBACzG,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,4DAA4D;QAC5D,eAAe;QACf,iDAAiD;QACjD,4DAA4D;QAC5D,MAAM,UAAU,GAAG,KAAK,EAAE,KAAwC,EAAE,EAAE;YACpE,OAAO,KAAK,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;gBAC7C,IAAI,KAAK,CAAC,KAAK,IAAI,wBAAwB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;oBACzD,MAAM,CAAC,OAAO,CAAC,qDAAqD,CAAC,CAAC;oBACtE,OAAO,EAAE,CAAC;gBACZ,CAAC;gBAED,MAAM,CAAC,OAAO,CAAC,wBAAwB,EAAE;oBACvC,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAC;gBAEH,IAAI,CAAC;oBACH,6DAA6D;oBAC7D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;oBAEvD,IAAI,CAAC,IAAI,EAAE,CAAC;wBACV,MAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;wBACzD,OAAO;4BACL,KAAK,EAAE,mBAAmB,KAAK,CAAC,MAAM,EAAE;yBACzC,CAAC;oBACJ,CAAC;oBAED,2DAA2D;oBAC3D,mEAAmE;oBACnE,MAAM,WAAW,GAAa,EAAE,CAAC;oBACjC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;oBACjE,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;wBACxB,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;4BAChB,KAAK,SAAS;gCAAE,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;gCAAC,MAAM;4BACjE,KAAK,UAAU;gCAAE,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;gCAAC,MAAM;4BACjE,KAAK,QAAQ;gCAAE,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;gCAAC,MAAM;4BAC7D,KAAK,UAAU;gCAAE,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;gCAAC,MAAM;4BACjE;gCAAS,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;gCAAC,MAAM;wBAC1D,CAAC;oBACH,CAAC;oBAED,4CAA4C;oBAC5C,IAAI,SAAS,GAAG,0BAA0B,IAAI,CAAC,IAAI,IAAI,aAAa,EAAE,CAAC;oBAEvE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;wBAClB,SAAS,IAAI,eAAe,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAC9C,CAAC;oBAED,SAAS,IAAI,OAAO,CAAC;oBAErB,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC3B,SAAS,IAAI,2BAA2B,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;wBACrE,SAAS,IAAI,0GAA0G,CAAC;oBAC1H,CAAC;yBAAM,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;wBACtB,SAAS,IAAI,gBAAgB,IAAI,CAAC,KAAK,MAAM,CAAC;wBAC9C,SAAS,IAAI,gFAAgF,CAAC;oBAChG,CAAC;yBAAM,CAAC;wBACN,SAAS,IAAI,uEAAuE,CAAC;oBACvF,CAAC;oBAED,MAAM,CAAC,OAAO,CAAC,gCAAgC,EAAE;wBAC/C,UAAU,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC;wBAClC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ;wBAC5B,gBAAgB,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;qBAC9C,CAAC,CAAC;oBAEH,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;oBAEzD,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE;wBAClC,UAAU,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;qBACrC,CAAC,CAAC;oBAEH,OAAO;wBACL,SAAS;wBACT,KAAK,EAAE,WAAW;wBAClB,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBACvC,mBAAmB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;qBACvC,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE;wBAC5B,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;qBAC9D,CAAC,CAAC;oBACH,OAAO;wBACL,KAAK,EAAE,sBAAsB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;qBACtF,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,4DAA4D;QAC5D,qDAAqD;QACrD,gEAAgE;QAChE,8DAA8D;QAC9D,0DAA0D;QAC1D,8DAA8D;QAC9D,YAAY;QACZ,gEAAgE;QAChE,gCAAgC;QAChC,4DAA4D;QAC5D,MAAM,gBAAgB,GAAG,KAAK,EAAE,KAAwC,EAAE,EAAE;YAC1E,OAAO,KAAK,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;gBACnD,MAAM,CAAC,OAAO,CAAC,gDAAgD,EAAE;oBAC/D,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAC;gBAEH,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;oBACvD,IAAI,CAAC,IAAI,EAAE,CAAC;wBACV,MAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;wBAC3E,OAAO,EAAE,KAAK,EAAE,mBAAmB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;oBACtD,CAAC;oBAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;oBACjE,MAAM,iBAAiB,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAC;oBAC9D,MAAM,OAAO,GAAG;wBACd,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,SAAS;wBAC5B,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,SAAS;wBAC9B,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,IAAI,SAAS;wBACjD,OAAO,EAAE,iBAAiB,CAAC,OAAO,IAAI,SAAS;wBAC/C,MAAM,EAAE,iBAAiB,CAAC,MAAM,IAAI,SAAS;wBAC7C,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,IAAI,SAAS;wBACjD,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;qBACtF,CAAC;oBAEF,MAAM,cAAc,GAAG,GAAG,EAAE;wBAC1B,MAAM,KAAK,GAAG;4BACZ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;4BACrC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE;4BACxC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE;4BACjD,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE;yBACvC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC7B,OAAO,KAAK,IAAI,0BAA0B,CAAC;oBAC7C,CAAC,CAAC;oBAEF,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACnB,MAAM,CAAC,IAAI,CAAC,qDAAqD,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;wBAC7F,OAAO;4BACL,KAAK,EAAE,cAAc,EAAE;4BACvB,aAAa,EAAE,KAAK;4BACpB,sBAAsB,EAAE,IAAI;4BAC5B,mBAAmB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;yBACvC,CAAC;oBACJ,CAAC;oBAED,IAAI,CAAC;wBACH,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;wBAElE,IAAI,UAAU,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;4BACtC,MAAM,CAAC,IAAI,CAAC,2DAA2D,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;4BACnG,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;4BAClD,OAAO,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC;wBAChD,CAAC;wBAED,MAAM,uBAAuB,GAAG,CAAC,CAAC,UAAU;4BAC1C,UAAU,CAAC,cAAc;4BACzB,CACE,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;gCACzC,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;gCAC9C,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;gCACvC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAC3C,CAAC;wBAEJ,IAAI,uBAAuB,EAAE,CAAC;4BAC5B,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,UAAW,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;gCACjG,MAAM,CAAC,IAAI,CAAC,kEAAkE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;gCAC1G,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gCAClD,OAAO,EAAE,KAAK,EAAE,mCAAmC,EAAE,CAAC;4BACxD,CAAC;4BAED,MAAM,CAAC,OAAO,CAAC,+BAA+B,EAAE;gCAC9C,MAAM,EAAE,KAAK,CAAC,MAAM;gCACpB,WAAW,EAAE,UAAW,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM;gCACjD,cAAc,EAAE,UAAW,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM;6BACxD,CAAC,CAAC;4BAEH,wCAAwC;4BACxC,MAAM,aAAa,GAIf,EAAE,CAAC;4BACP,MAAM,YAAY,GAAG,UAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;4BACvD,IACE,YAAY;gCACZ,wCAAwC,CACtC,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,EAC3E,YAAY,CACb,EACD,CAAC;gCACD,aAAa,CAAC,IAAI,GAAG,YAAY,CAAC;4BACpC,CAAC;4BACD,IAAI,UAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE;gCAAE,aAAa,CAAC,KAAK,GAAG,UAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;4BAC5F,IAAI,UAAW,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE;gCAAE,aAAa,CAAC,QAAQ,GAAG,UAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;4BAEzG,MAAM,eAAe,GAAuC,EAAE,CAAC;4BAC/D,IAAI,UAAW,CAAC,OAAO,CAAC,OAAO;gCAAE,eAAe,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAW,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;4BAChH,IAAI,UAAW,CAAC,OAAO,CAAC,QAAQ;gCAAE,eAAe,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;4BACnH,IAAI,UAAW,CAAC,OAAO,CAAC,MAAM;gCAAE,eAAe,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAW,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;4BAC7G,IAAI,UAAW,CAAC,OAAO,CAAC,QAAQ;gCAAE,eAAe,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;4BACnH,IAAI,UAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;gCACzC,KAAK,MAAM,CAAC,IAAI,UAAW,CAAC,OAAO,CAAC,QAAQ;oCAAE,eAAe,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;4BACpG,CAAC;4BACD,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gCAC/B,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gCACzE,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;gCAClE,MAAM,IAAI,GAAG,eAAe;qCACzB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;qCACjE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gCAClD,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC;oCACzC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,EAAE,GAAG,eAAe,CAAC;oCACjE,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,eAAe,CAAC,CAAC;gCAClC,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;4BAC3D,CAAC;4BAED,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gCAC1C,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;4BAC9D,CAAC;4BAED,sEAAsE;4BACtE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gCACjB,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gCACxE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;gCACtF,IAAI,SAAS,EAAE,CAAC;oCACd,MAAM,CAAC,IAAI,CAAC,yDAAyD,EAAE;wCACrE,OAAO,EAAE,KAAK,CAAC,MAAM;wCACrB,QAAQ,EAAE,SAAS,CAAC,EAAE;qCACvB,CAAC,CAAC;oCACH,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;oCAC/D,OAAO,EAAE,KAAK,EAAE,+BAA+B,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC;gCAClE,CAAC;4BACH,CAAC;4BAED,2DAA2D;4BAC3D,6DAA6D;4BAC7D,8CAA8C;4BAC9C,MAAM,eAAe,GAAG;gCACtB,UAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,UAAW,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE;gCAC3E,UAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,iBAAiB,UAAW,CAAC,QAAQ,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE;gCACtF,UAAW,CAAC,QAAQ,CAAC,GAAG,IAAI,EAAE;gCAC9B,UAAW,CAAC,SAAS,CAAC,OAAO,IAAI,EAAE;gCACnC,UAAW,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,UAAW,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gCAC5G,UAAW,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,wBAAwB,UAAW,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;6BACtH,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;4BAE7B,OAAO;gCACL,KAAK,EAAE,eAAe;gCACtB,aAAa,EAAE,KAAK;gCACpB,sBAAsB,EAAE,IAAI;gCAC5B,WAAW,EAAE,IAAI;gCACjB,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gCACvC,mBAAmB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;6BACvC,CAAC;wBACJ,CAAC;wBAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;4BACjB,MAAM,CAAC,IAAI,CAAC,oDAAoD,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;4BAC5F,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;4BAClD,OAAO,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC;wBAC9D,CAAC;wBACD,MAAM,CAAC,IAAI,CAAC,qEAAqE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;oBAC/G,CAAC;oBAAC,OAAO,SAAS,EAAE,CAAC;wBACnB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;4BACjB,MAAM,CAAC,IAAI,CAAC,4CAA4C,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;4BACpF,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;4BAClD,OAAO,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC;wBACvD,CAAC;wBACD,MAAM,CAAC,IAAI,CAAC,wDAAwD,EAAE;4BACpE,MAAM,EAAE,KAAK,CAAC,MAAM;4BACpB,KAAK,EAAE,SAAS,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;yBAC1E,CAAC,CAAC;oBACL,CAAC;oBAED,OAAO;wBACL,KAAK,EAAE,cAAc,EAAE;wBACvB,aAAa,EAAE,KAAK;wBACpB,sBAAsB,EAAE,IAAI;wBAC5B,mBAAmB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;qBACvC,CAAC;gBACJ,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE;wBACnC,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;qBACxD,CAAC,CAAC;oBACH,OAAO,EAAE,KAAK,EAAE,yBAAyB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBAChG,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,4DAA4D;QAC5D,2BAA2B;QAC3B,wEAAwE;QACxE,2EAA2E;QAC3E,8EAA8E;QAC9E,+EAA+E;QAC/E,mDAAmD;QACnD,4DAA4D;QAC5D,MAAM,qBAAqB,GAAG,KAAK,EAAE,KAAwC,EAAE,EAAE;YAC/E,OAAO,KAAK,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;gBACxD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;oBACjB,MAAM,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;oBACnD,OAAO,EAAE,KAAK,EAAE,0CAA0C,EAAE,CAAC;gBAC/D,CAAC;gBAED,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;oBACvB,sEAAsE;oBACtE,MAAM,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;oBAC1E,OAAO,EAAE,CAAC;gBACZ,CAAC;gBAED,MAAM,CAAC,OAAO,CAAC,oCAAoC,EAAE;oBACnD,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM;iBAChC,CAAC,CAAC;gBAEH,MAAM,iBAAiB,GAAqB,EAAE,CAAC;gBAE/C,IAAI,CAAC;oBACH,MAAM,aAAa,GAAG,cAAc,CAAC,QAAQ,EAAE,EAAE,YAAY,CAAC;oBAE9D,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBAClC,aAAa,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,CAAC;oBACrE,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC;oBAChD,iBAAiB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;oBAChF,aAAa,EAAE,CAAC;wBACd,IAAI,EAAE,WAAW;wBACjB,IAAI,EAAE,oBAAoB;wBAC1B,UAAU,EAAE,WAAW;wBACvB,OAAO,EAAE,mBAAmB,MAAM,CAAC,QAAQ,CAAC,MAAM,aAAa;qBAChE,CAAC,CAAC;oBAEH,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACjC,MAAM,CAAC,OAAO,CAAC,2CAA2C,CAAC,CAAC;wBAC5D,OAAO;4BACL,YAAY,EAAE,iBAAiB;yBAChC,CAAC;oBACJ,CAAC;oBAED,MAAM,CAAC,OAAO,CAAC,YAAY,MAAM,CAAC,QAAQ,CAAC,MAAM,+BAA+B,EAAE;wBAChF,MAAM,EAAE,KAAK,CAAC,MAAM;qBACrB,CAAC,CAAC;oBAEH,IAAI,OAAO,GAAG,CAAC,CAAC;oBAChB,IAAI,iBAAiB,GAAG,CAAC,CAAC;oBAC1B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBAChC,IAAI,CAAC;4BACH,oEAAoE;4BACpE,uEAAuE;4BACvE,MAAM,YAAY,GAAG,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC;4BAC7C,MAAM,UAAU,GAAG,YAAY,IAAI,CAAC,CAAC,YAAY;gCAC/C,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,YAAY,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;gCAC3E,CAAC,CAAC,SAAS,CAAC;4BAEd,MAAM,aAAa,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,YAAY,EAAE;gCACnE,MAAM,EAAE,KAAK,CAAC,MAAM;gCACpB,aAAa,EAAE,CAAC,CAAC,IAAI;gCACrB,IAAI,EAAE,CAAC,CAAC,IAAI;gCACZ,aAAa,EAAE,QAAQ;gCACvB,QAAQ,EAAE,YAAY;gCACtB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gCACrC,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,MAAM;oCAC/B,CAAC,CAAC,EAAE,gBAAgB,EAAE,aAAsB,EAAE,kBAAkB,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;oCAC5F,CAAC,CAAC,EAAE,CAAC;6BACR,CAAC,CAAC;4BAEH,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;gCAC1B,OAAO,EAAE,CAAC;4BACZ,CAAC;iCAAM,IAAI,aAAa,CAAC,WAAW,EAAE,CAAC;gCACrC,iBAAiB,EAAE,CAAC;4BACtB,CAAC;iCAAM,IAAI,aAAa,CAAC,KAAK,EAAE,CAAC;gCAC/B,MAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE;oCACrC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC;oCAC7B,KAAK,EAAE,aAAa,CAAC,KAAK;iCAC3B,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACb,MAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE;gCACpC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC;gCAC7B,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;6BACxD,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;oBAED,MAAM,CAAC,OAAO,CAAC,WAAW,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,gBAAgB,iBAAiB,8BAA8B,EAAE;wBAC1H,MAAM,EAAE,KAAK,CAAC,MAAM;qBACrB,CAAC,CAAC;oBAEH,OAAO;wBACL,YAAY,EAAE,iBAAiB;wBAC/B,mBAAmB,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE;qBAClD,CAAC;gBACJ,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE;wBAC3C,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;qBACxD,CAAC,CAAC;oBACH,OAAO;wBACL,YAAY,EAAE,iBAAiB;qBAChC,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,4DAA4D;QAC5D,qBAAqB;QACrB,2EAA2E;QAC3E,4DAA4D;QAE5D;;WAEG;QACH,MAAM,mBAAmB,GAAG,CAAC,KAAwC,EAAU,EAAE;YAC/E,6CAA6C;YAC7C,IAAI,KAAK,CAAC,aAAa,KAAK,OAAO,EAAE,CAAC;gBACpC,MAAM,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;gBAClD,OAAO,GAAG,CAAC;YACb,CAAC;YAED,iEAAiE;YACjE,IAAI,KAAK,CAAC,aAAa,KAAK,UAAU,EAAE,CAAC;gBACvC,MAAM,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC;gBAC3D,OAAO,eAAe,CAAC;YACzB,CAAC;YAED,yDAAyD;YACzD,iEAAiE;YACjE,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;gBACxB,MAAM,CAAC,OAAO,CAAC,kDAAkD,EAAE;oBACjE,WAAW,EAAE,KAAK,CAAC,eAAe;iBACnC,CAAC,CAAC;gBACH,OAAO,GAAG,CAAC;YACb,CAAC;YAED,0CAA0C;YAC1C,IAAI,KAAK,CAAC,sBAAsB,EAAE,CAAC;gBACjC,6EAA6E;gBAC7E,IAAI,KAAK,CAAC,KAAK,IAAI,wBAAwB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;oBACzD,yEAAyE;oBACzE,wEAAwE;oBACxE,wEAAwE;oBACxE,oCAAoC;oBACpC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;wBACtB,MAAM,CAAC,OAAO,CAAC,6DAA6D,CAAC,CAAC;wBAC9E,OAAO,oBAAoB,CAAC;oBAC9B,CAAC;oBACD,MAAM,CAAC,OAAO,CAAC,kEAAkE,CAAC,CAAC;oBACnF,OAAO,GAAG,CAAC;gBACb,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,OAAO,CAAC,kEAAkE,CAAC,CAAC;oBACnF,OAAO,QAAQ,CAAC;gBAClB,CAAC;YACH,CAAC;YAED,sCAAsC;YACtC,MAAM,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC;YAChD,OAAO,GAAG,CAAC;QACb,CAAC,CAAC;QAGF,4DAA4D;QAC5D,iBAAiB;QACjB,8DAA8D;QAC9D,4DAA4D;QAE5D,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,oBAAoB,CAAC;YACnD,gBAAgB;aACf,OAAO,CAAC,aAAa,EAAE,cAAc,CAAC;aACtC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC;aAC7B,OAAO,CAAC,oBAAoB,EAAE,qBAAqB,CAAC;aACpD,OAAO,CAAC,eAAe,EAAE,gBAAgB,CAAC;YAE3C,yBAAyB;aACxB,OAAO,CAAC,KAAK,EAAE,aAAa,CAAC;YAE9B,uCAAuC;aACtC,mBAAmB,CAClB,aAAa,EACb,mBAAmB,EACnB;YACE,aAAa,EAAE,eAAe,EAAQ,uCAAuC;YAC7E,kBAAkB,EAAE,oBAAoB,EAAE,kDAAkD;YAC5F,MAAM,EAAE,QAAQ,EAAsB,0CAA0C;YAChF,CAAC,GAAG,CAAC,EAAE,GAAG,CAA4B,qDAAqD;SAC5F,CACF;YAED,mEAAmE;YACnE,+EAA+E;aAC9E,OAAO,CAAC,oBAAoB,EAAE,GAAG,CAAC;YAEnC,oEAAoE;YACpE,0DAA0D;aACzD,mBAAmB,CAClB,eAAe,EACf,CAAC,KAAwC,EAAE,EAAE;YAC3C,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACrC,MAAM,CAAC,OAAO,CAAC,8DAA8D,CAAC,CAAC;gBAC/E,OAAO,oBAAoB,CAAC;YAC9B,CAAC;YACD,MAAM,CAAC,OAAO,CAAC,+FAA+F,CAAC,CAAC;YAChH,OAAO,GAAG,CAAC;QACb,CAAC,EACD;YACE,kBAAkB,EAAE,oBAAoB;YACxC,CAAC,GAAG,CAAC,EAAE,GAAG;SACX,CACF;YAED,0EAA0E;aACzE,mBAAmB,CAClB,QAAQ,EACR,CAAC,MAAyC,EAAE,EAAE;YAC5C,IAAI,IAAI,CAAC,YAAY;gBAAE,OAAO,oBAAoB,CAAC;YACnD,OAAO,GAAG,CAAC;QACb,CAAC,EACD;YACE,kBAAkB,EAAE,oBAAoB;YACxC,CAAC,GAAG,CAAC,EAAE,GAAG;SACX,CACF,CAAC;QAEJ,MAAM,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;QAC3C,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC5B,CAAC;CACF","sourcesContent":["import { StateGraph, START, END } from \"@langchain/langgraph\";\nimport { EnrichmentGraphState } from \"./enrichment.state.js\";\nimport { EnrichmentGraphDatabase, PremiseProvenance } from \"../shared/interfaces/database.interface.js\";\nimport { Scraper } from \"../shared/interfaces/scraper.interface.js\";\nimport type { ProfileEnricher } from \"../shared/interfaces/enrichment.interface.js\";\nimport { shouldEnrichGhostDisplayNameFromParallel, isEnrichedNameMeaningful } from \"./enrichment.enricher.js\";\nimport { socialsToEnrichmentRequest } from \"../shared/utils/social-label.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport type { QuestionerEnqueueFn } from \"../questioner/questioner.types.js\";\nimport { timed } from \"../shared/observability/performance.js\";\nimport { requestContext } from \"../shared/observability/request-context.js\";\nimport type { DebugMetaAgent } from \"../chat/chat-streaming.types.js\";\nimport { PremiseDecomposer } from \"../premise/premise.decomposer.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\n/**\n * Compiled premise graph interface. Matches the invoke signature of a compiled LangGraph.\n * Accepted as an optional dependency so write-mode input can be decomposed into premises.\n */\nexport interface CompiledPremiseGraph {\n invoke(input: {\n userId: string;\n assertionText: string;\n tier: 'assertive' | 'contextual';\n operationMode: 'create';\n /** Volatile premises auto-retract once their validity window lapses. */\n volatile?: boolean;\n /** ISO timestamp after which a contextual premise is no longer valid. */\n validUntil?: string;\n provenanceSource?: PremiseProvenance['source'];\n provenanceSourceId?: string;\n }): Promise<{\n premise?: { id: string } | undefined;\n /** Set when the create was skipped because a near-duplicate already exists. */\n duplicateOf?: { premiseId: string; assertionText: string; similarity: number } | undefined;\n error?: string | undefined;\n }>;\n}\n\nconst logger = protocolLogger(\"EnrichmentGraphFactory\");\n\n/** Minimum length for input to be considered meaningful (e.g. not just \"Yes\") */\nconst MIN_MEANINGFUL_INPUT_LENGTH = 20;\n\n/** Phrases that are confirmations only and must not be used as profile content */\nconst CONFIRMATION_PHRASES = new Set([\n \"yes\", \"yeah\", \"yep\", \"sure\", \"ok\", \"okay\", \"go ahead\", \"do it\", \"please\",\n \"correct\", \"right\", \"exactly\", \"absolutely\", \"of course\", \"sounds good\",\n \"create one\", \"create it\", \"set one up\", \"set it up\", \"create my profile\",\n \"create profile\", \"set up profile\", \"create a profile\"\n]);\n\n/**\n * Returns true only if the input contains real profile information.\n * Confirmation-only replies (e.g. \"Yes\" to \"Would you like to create a profile?\")\n * must not be treated as input so we ask for user info / use scraper instead of inventing a profile.\n */\nfunction isMeaningfulProfileInput(input: string | undefined): boolean {\n if (!input || typeof input !== \"string\") return false;\n const trimmed = input.trim();\n if (trimmed.length < MIN_MEANINGFUL_INPUT_LENGTH) return false;\n const lower = trimmed.toLowerCase();\n if (CONFIRMATION_PHRASES.has(lower)) return false;\n if (CONFIRMATION_PHRASES.has(lower.replace(/[.!?]+$/, \"\"))) return false;\n return true;\n}\n\n\n/**\n * Factory class to build and compile the Profile Generation Graph.\n *\n * Flow:\n * 1. check_state - Detect whether profile needs generation\n * 2. Conditional routing based on operation mode and missing components:\n * - Query mode: Return immediately (fast path)\n * - Write mode: Generate only what's needed\n * 3. Profile generation (if needed)\n * 4. Save profile to DB\n *\n * Key Features:\n * - Read/Write separation (query vs write)\n * - Conditional generation (skip generation if profile already exists)\n */\nexport class EnrichmentGraphFactory {\n constructor(\n private database: EnrichmentGraphDatabase,\n private scraper: Scraper,\n private enricher?: ProfileEnricher,\n private questionerEnqueue?: QuestionerEnqueueFn,\n private premiseGraph?: CompiledPremiseGraph,\n ) { }\n\n public createGraph() {\n const premiseDecomposer = new PremiseDecomposer();\n\n // ─────────────────────────────────────────────────────────\n // NODE: Check State\n // Loads existing profile from DB and detects what needs generation:\n // - Profile missing\n // - User information insufficient for scraping\n // ─────────────────────────────────────────────────────────\n const checkStateNode = async (state: typeof EnrichmentGraphState.State) => {\n return timed(\"ProfileGraph.checkState\", async () => {\n if (!state.userId) {\n logger.error(\"Missing userId\");\n return {\n error: \"userId is required\"\n };\n }\n\n logger.verbose(\"Checking profile state...\", {\n userId: state.userId,\n operationMode: state.operationMode,\n forceUpdate: state.forceUpdate\n });\n\n try {\n const profile = await this.database.getProfile(state.userId) as any;\n // \"Has a profile\" now means the user has been enriched into ACTIVE premises\n // (the user_profiles replacement). `getProfile` returns a users-sourced row\n // for every existing user, so its presence no longer signals enrichment --\n // the premise graph is the source of truth for whether generation has run.\n const hasBeenEnriched = (await this.database.getPremisesForUser(state.userId, 'ACTIVE')).length > 0;\n\n // Query mode: Just return the profile (fast path)\n if (state.operationMode === 'query') {\n logger.verbose(\"🚀 Query mode - returning existing profile (fast path)\", {\n hasProfile: hasBeenEnriched\n });\n const profileWithId = hasBeenEnriched ? await this.database.getProfileByUserId(state.userId) : null;\n return {\n profile: hasBeenEnriched ? (profile || undefined) : undefined,\n readResult: hasBeenEnriched\n ? {\n hasProfile: true,\n // Thin identity only. The structured skills/interests attributes are\n // retired (user_profiles removal, WS6); the rich identity text now\n // comes from the global user_context, injected by read_user_profiles.\n profile: {\n id: profileWithId?.id,\n name: profile?.identity?.name,\n bio: profile?.identity?.bio,\n location: profile?.identity?.location,\n },\n }\n : {\n hasProfile: false,\n message:\n \"You don't have a profile yet. Would you like to create one? You can share your LinkedIn, GitHub, or X/Twitter profile, or just tell me about yourself.\",\n },\n };\n }\n\n // Write mode: Detect what needs generation\n // Treat confirmation-only input (e.g. \"Yes\") as no input so we ask for info / use scraper\n const hasMeaningfulInput = !!state.input && isMeaningfulProfileInput(state.input);\n const needsProfileGeneration = !hasBeenEnriched || (state.forceUpdate && hasMeaningfulInput);\n\n // Check if we need to scrape (profile generation needed but no meaningful input provided)\n const willNeedScraping = needsProfileGeneration && !hasMeaningfulInput;\n\n // If we need to scrape, check if we have sufficient user information\n let needsUserInfo = false;\n const missingUserInfo: string[] = [];\n\n if (willNeedScraping) {\n logger.verbose(\"Will need scraping - checking user information...\");\n\n const user = await this.database.getUser(state.userId);\n\n if (!user) {\n logger.error(\"User not found\", { userId: state.userId });\n return {\n error: `User not found: ${state.userId}`\n };\n }\n\n // Check what information we have from the user table (schema: users)\n // Required fields: email, name (always present)\n // Optional fields: intro, avatar, location, socials\n\n const socials = await this.database.getUserSocials(state.userId);\n const hasSocials = socials.length > 0;\n\n // Check if name is a full name (not just email username)\n // For scraping to work well, we need first + last name\n const hasMeaningfulName = user.name &&\n user.name.trim() !== '' &&\n !user.name.includes('@') &&\n user.name.split(/\\s+/).filter(Boolean).length >= 2;\n\n const hasLocation = !!(user.location && user.location.trim() !== '');\n\n // Minimum requirement for accurate scraping:\n // - At least ONE social link (preferred - most reliable for finding the right person)\n // - OR a full name (first + last) - less reliable but workable\n // Location helps disambiguate but is not required\n\n const hasMinimumInfo = hasSocials || hasMeaningfulName;\n\n if (!hasMinimumInfo) {\n needsUserInfo = true;\n\n // Build precise list of what's missing and would help\n if (!hasSocials) {\n missingUserInfo.push('social_urls');\n }\n if (!hasMeaningfulName) {\n missingUserInfo.push('full_name');\n }\n if (!hasLocation) {\n missingUserInfo.push('location'); // Nice to have\n }\n\n logger.verbose(\"⚠️ Insufficient user information for scraping\", {\n hasSocials,\n hasMeaningfulName,\n hasLocation,\n currentName: user.name,\n missingUserInfo\n });\n } else {\n logger.verbose(\"✅ Sufficient user information for scraping\", {\n hasSocials,\n hasMeaningfulName,\n hasLocation,\n willProceedWith: hasSocials ? 'social links' : 'full name'\n });\n }\n }\n\n logger.verbose(\"📊 State detection complete\", {\n hasProfile: hasBeenEnriched,\n needsProfileGeneration,\n needsUserInfo,\n missingUserInfo,\n forceUpdate: state.forceUpdate,\n hasInput: !!state.input,\n hasMeaningfulInput,\n });\n\n return {\n // Only treat the (users-sourced) profile as existing state when the user has\n // actually been enriched; un-enriched users keep `undefined` so the generate\n // path runs from scratch rather than merging into an empty users row.\n profile: hasBeenEnriched ? (profile || undefined) : undefined,\n needsProfileGeneration,\n needsUserInfo,\n missingUserInfo\n };\n } catch (error) {\n logger.error(\"Failed to load profile\", {\n error: error instanceof Error ? error.message : String(error)\n });\n return {\n profile: undefined,\n error: `Failed to load profile from database: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n });\n };\n\n // ─────────────────────────────────────────────────────────\n // NODE: Scrape\n // Scrapes data from web if input is not provided\n // ─────────────────────────────────────────────────────────\n const scrapeNode = async (state: typeof EnrichmentGraphState.State) => {\n return timed(\"ProfileGraph.scrape\", async () => {\n if (state.input && isMeaningfulProfileInput(state.input)) {\n logger.verbose(\"Meaningful input already provided - skipping scrape\");\n return {};\n }\n\n logger.verbose(\"Starting web scrape...\", {\n userId: state.userId\n });\n\n try {\n // Fetch user details to construct objective for web scraping\n const user = await this.database.getUser(state.userId);\n\n if (!user) {\n logger.error(\"User not found\", { userId: state.userId });\n return {\n error: `User not found: ${state.userId}`\n };\n }\n\n // Build scraping objective from available user information\n // Priority: social links (most reliable) > name + location > email\n const socialParts: string[] = [];\n const socials = await this.database.getUserSocials(state.userId);\n for (const s of socials) {\n switch (s.label) {\n case 'twitter': socialParts.push(`X/Twitter: ${s.value}`); break;\n case 'linkedin': socialParts.push(`LinkedIn: ${s.value}`); break;\n case 'github': socialParts.push(`GitHub: ${s.value}`); break;\n case 'telegram': socialParts.push(`Telegram: ${s.value}`); break;\n default: socialParts.push(`Website: ${s.value}`); break;\n }\n }\n\n // Construct objective based on what we have\n let objective = `Find information about ${user.name || 'this person'}`;\n\n if (user.location) {\n objective += ` located in ${user.location}`;\n }\n\n objective += '.\\n\\n';\n\n if (socialParts.length > 0) {\n objective += `Their social profiles:\\n${socialParts.join('\\n')}\\n\\n`;\n objective += 'Use these links to find accurate information about their professional background, skills, and interests.';\n } else if (user.email) {\n objective += `Their email: ${user.email}\\n\\n`;\n objective += 'Search for professional information, skills, and background about this person.';\n } else {\n objective += 'Search for professional information and background about this person.';\n }\n\n logger.verbose(\"Constructed scraping objective\", {\n hasSocials: socialParts.length > 0,\n hasLocation: !!user.location,\n objectivePreview: objective.substring(0, 100)\n });\n\n const scrapedData = await this.scraper.scrape(objective);\n\n logger.verbose(\"✅ Scrape complete\", {\n dataLength: scrapedData?.length || 0\n });\n\n return {\n objective,\n input: scrapedData,\n activeSocialIds: socials.map(s => s.id),\n operationsPerformed: { scraped: true }\n };\n } catch (error) {\n logger.error(\"Scrape failed\", {\n error: error instanceof Error ? error.message : String(error)\n });\n return {\n error: `Web scrape failed: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n });\n };\n\n // ─────────────────────────────────────────────────────────\n // NODE: Auto-Generate (Parallel Chat API enrichment)\n // Calls enrichUserProfile to get structured data, then builds a\n // text blob as input for the decompose → aggregate → generate\n // pipeline. This ensures enriched users get premises with\n // embeddings, making them discoverable via premise-to-premise\n // matching.\n // On failure, falls back to basic user info for LLM generation.\n // Used in 'generate' mode only.\n // ─────────────────────────────────────────────────────────\n const autoGenerateNode = async (state: typeof EnrichmentGraphState.State) => {\n return timed(\"ProfileGraph.autoGenerate\", async () => {\n logger.verbose(\"Starting auto-generate via Chat API enrichment\", {\n userId: state.userId,\n });\n\n try {\n const user = await this.database.getUser(state.userId);\n if (!user) {\n logger.error(\"User not found for auto-generate\", { userId: state.userId });\n return { error: `User not found: ${state.userId}` };\n }\n\n const socials = await this.database.getUserSocials(state.userId);\n const enrichmentSocials = socialsToEnrichmentRequest(socials);\n const request = {\n name: user.name || undefined,\n email: user.email || undefined,\n linkedin: enrichmentSocials.linkedin || undefined,\n twitter: enrichmentSocials.twitter || undefined,\n github: enrichmentSocials.github || undefined,\n telegram: enrichmentSocials.telegram || undefined,\n websites: enrichmentSocials.websites?.length ? enrichmentSocials.websites : undefined,\n };\n\n const buildBasicInfo = () => {\n const parts = [\n user.name ? `Name: ${user.name}` : '',\n user.email ? `Email: ${user.email}` : '',\n user.location ? `Location: ${user.location}` : '',\n user.intro ? `Bio: ${user.intro}` : '',\n ].filter(Boolean).join('\\n');\n return parts || \"No information available\";\n };\n\n if (!this.enricher) {\n logger.warn(\"No enricher configured — falling back to basic info\", { userId: state.userId });\n return {\n input: buildBasicInfo(),\n needsUserInfo: false,\n needsProfileGeneration: true,\n operationsPerformed: { scraped: true },\n };\n }\n\n try {\n const enrichment = await this.enricher.enrichUserProfile(request);\n\n if (enrichment && !enrichment.isHuman) {\n logger.info(\"Enrichment detected non-human entity, soft-deleting ghost\", { userId: state.userId });\n await this.database.softDeleteGhost(state.userId);\n return { error: \"Non-human entity detected\" };\n }\n\n const hasMeaningfulEnrichment = !!enrichment &&\n enrichment.confidentMatch &&\n (\n enrichment.identity.bio.trim().length > 0 ||\n enrichment.narrative.context.trim().length > 0 ||\n enrichment.attributes.skills.length > 0 ||\n enrichment.attributes.interests.length > 0\n );\n\n if (hasMeaningfulEnrichment) {\n if (user.isGhost && !isEnrichedNameMeaningful(user.email || '', enrichment!.identity.name || '')) {\n logger.info(\"Enrichment has content but no real name for ghost, soft-deleting\", { userId: state.userId });\n await this.database.softDeleteGhost(state.userId);\n return { error: \"No real name found for ghost user\" };\n }\n\n logger.verbose(\"Chat API enrichment succeeded\", {\n userId: state.userId,\n skillsCount: enrichment!.attributes.skills.length,\n interestsCount: enrichment!.attributes.interests.length,\n });\n\n // Update user record with enriched data\n const updatePayload: {\n name?: string;\n intro?: string;\n location?: string;\n } = {};\n const enrichedName = enrichment!.identity.name?.trim();\n if (\n enrichedName &&\n shouldEnrichGhostDisplayNameFromParallel(\n { isGhost: !!user.isGhost, name: user.name ?? '', email: user.email ?? '' },\n enrichedName,\n )\n ) {\n updatePayload.name = enrichedName;\n }\n if (enrichment!.identity.bio?.trim()) updatePayload.intro = enrichment!.identity.bio.trim();\n if (enrichment!.identity.location?.trim()) updatePayload.location = enrichment!.identity.location.trim();\n\n const enrichedSocials: { label: string; value: string }[] = [];\n if (enrichment!.socials.twitter) enrichedSocials.push({ label: 'twitter', value: enrichment!.socials.twitter });\n if (enrichment!.socials.linkedin) enrichedSocials.push({ label: 'linkedin', value: enrichment!.socials.linkedin });\n if (enrichment!.socials.github) enrichedSocials.push({ label: 'github', value: enrichment!.socials.github });\n if (enrichment!.socials.telegram) enrichedSocials.push({ label: 'telegram', value: enrichment!.socials.telegram });\n if (enrichment!.socials.websites?.length) {\n for (const w of enrichment!.socials.websites) enrichedSocials.push({ label: 'custom', value: w });\n }\n if (enrichedSocials.length > 0) {\n const existingSocials = await this.database.getUserSocials(state.userId);\n const enrichedLabels = new Set(enrichedSocials.map(s => s.label));\n const kept = existingSocials\n .filter(s => !enrichedLabels.has(s.label) || s.label === 'custom')\n .map(s => ({ label: s.label, value: s.value }));\n const merged = enrichedLabels.has('custom')\n ? [...kept.filter(s => s.label !== 'custom'), ...enrichedSocials]\n : [...kept, ...enrichedSocials];\n await this.database.setUserSocials(state.userId, merged);\n }\n\n if (Object.keys(updatePayload).length > 0) {\n await this.database.updateUser(state.userId, updatePayload);\n }\n\n // Post-enrichment dedup: check if this ghost matches an existing user\n if (user.isGhost) {\n const currentSocials = await this.database.getUserSocials(state.userId);\n const duplicate = await this.database.findDuplicateUser(state.userId, currentSocials);\n if (duplicate) {\n logger.info(\"Post-enrichment dedup: merging ghost into existing user\", {\n ghostId: state.userId,\n targetId: duplicate.id,\n });\n await this.database.mergeGhostUser(state.userId, duplicate.id);\n return { error: `Merged as duplicate of user ${duplicate.id}` };\n }\n }\n\n // Build a text blob from the enrichment result so it flows\n // through premise decomposition (when available) rather than\n // bypassing premises via prePopulatedProfile.\n const enrichmentParts = [\n enrichment!.identity.name ? `My name is ${enrichment!.identity.name}.` : '',\n enrichment!.identity.location ? `I am based in ${enrichment!.identity.location}.` : '',\n enrichment!.identity.bio || '',\n enrichment!.narrative.context || '',\n enrichment!.attributes.skills.length ? `My skills include ${enrichment!.attributes.skills.join(', ')}.` : '',\n enrichment!.attributes.interests.length ? `My interests include ${enrichment!.attributes.interests.join(', ')}.` : '',\n ].filter(Boolean).join('\\n');\n\n return {\n input: enrichmentParts,\n needsUserInfo: false,\n needsProfileGeneration: true,\n forceUpdate: true,\n activeSocialIds: socials.map(s => s.id),\n operationsPerformed: { scraped: true },\n };\n }\n\n if (user.isGhost) {\n logger.info(\"Low-confidence enrichment for ghost, soft-deleting\", { userId: state.userId });\n await this.database.softDeleteGhost(state.userId);\n return { error: \"Enrichment not confident for ghost user\" };\n }\n logger.warn(\"Chat API returned low-signal enrichment, falling back to basic info\", { userId: state.userId });\n } catch (enrichErr) {\n if (user.isGhost) {\n logger.info(\"Enrichment failed for ghost, soft-deleting\", { userId: state.userId });\n await this.database.softDeleteGhost(state.userId);\n return { error: \"Enrichment failed for ghost user\" };\n }\n logger.warn(\"Chat API enrichment failed, falling back to basic info\", {\n userId: state.userId,\n error: enrichErr instanceof Error ? enrichErr.message : String(enrichErr),\n });\n }\n\n return {\n input: buildBasicInfo(),\n needsUserInfo: false,\n needsProfileGeneration: true,\n operationsPerformed: { scraped: true },\n };\n } catch (err) {\n logger.error(\"Auto-generate failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return { error: `Auto-generate failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n });\n };\n\n // ─────────────────────────────────────────────────────────\n // NODE: Decompose Premises\n // Decomposes free-text input (chat or scraped) into individual premises\n // and creates each via the premise graph. Premise creation is the terminal\n // effect: premise lifecycle events drive user_context regeneration downstream\n // (the legacy aggregate→generate→save profile tail was removed in WS8/IND-365,\n // along with the user_profiles table it wrote to).\n // ─────────────────────────────────────────────────────────\n const decomposePremisesNode = async (state: typeof EnrichmentGraphState.State) => {\n return timed(\"ProfileGraph.decomposePremises\", async () => {\n if (!state.input) {\n logger.error(\"No input for premise decomposition\");\n return { error: \"Input required for premise decomposition\" };\n }\n\n if (!this.premiseGraph) {\n // No premise graph injected — nothing to decompose into. End the run.\n logger.warn(\"No premise graph injected — skipping premise decomposition\");\n return {};\n }\n\n logger.verbose(\"Decomposing input into premises...\", {\n userId: state.userId,\n inputLength: state.input.length,\n });\n\n const agentTimingsAccum: DebugMetaAgent[] = [];\n\n try {\n const _traceEmitter = requestContext.getStore()?.traceEmitter;\n\n const decomposeStart = Date.now();\n _traceEmitter?.({ type: \"agent_start\", name: \"premise-decomposer\" });\n const result = await premiseDecomposer.invoke(state.input);\n const decomposeMs = Date.now() - decomposeStart;\n agentTimingsAccum.push({ name: \"premise.decomposer\", durationMs: decomposeMs });\n _traceEmitter?.({\n type: \"agent_end\",\n name: \"premise-decomposer\",\n durationMs: decomposeMs,\n summary: `Decomposed into ${result.premises.length} premise(s)`,\n });\n\n if (result.premises.length === 0) {\n logger.verbose(\"No premises extracted — nothing to create\");\n return {\n agentTimings: agentTimingsAccum,\n };\n }\n\n logger.verbose(`Creating ${result.premises.length} premise(s) via premise graph`, {\n userId: state.userId,\n });\n\n let created = 0;\n let skippedDuplicates = 0;\n for (const p of result.premises) {\n try {\n // Contextual premises carry an LLM-inferred validity window and are\n // volatile (auto-retract on expiry); assertive premises do not expire.\n const isContextual = p.tier === 'contextual';\n const validUntil = isContextual && p.validityDays\n ? new Date(Date.now() + p.validityDays * 24 * 60 * 60 * 1000).toISOString()\n : undefined;\n\n const premiseResult = await invokeWithAbortSignal(this.premiseGraph, {\n userId: state.userId,\n assertionText: p.text,\n tier: p.tier,\n operationMode: 'create',\n volatile: isContextual,\n ...(validUntil ? { validUntil } : {}),\n ...(state.activeSocialIds?.length\n ? { provenanceSource: 'integration' as const, provenanceSourceId: state.activeSocialIds[0] }\n : {}),\n });\n\n if (premiseResult.premise) {\n created++;\n } else if (premiseResult.duplicateOf) {\n skippedDuplicates++;\n } else if (premiseResult.error) {\n logger.warn(\"Premise creation failed\", {\n text: p.text.substring(0, 60),\n error: premiseResult.error,\n });\n }\n } catch (err) {\n logger.warn(\"Premise creation threw\", {\n text: p.text.substring(0, 60),\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n logger.verbose(`Created ${created}/${result.premises.length} premise(s) (${skippedDuplicates} skipped as near-duplicates)`, {\n userId: state.userId,\n });\n\n return {\n agentTimings: agentTimingsAccum,\n operationsPerformed: { decomposedPremises: true },\n };\n } catch (err) {\n logger.error(\"Premise decomposition failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return {\n agentTimings: agentTimingsAccum,\n };\n }\n });\n };\n\n // ─────────────────────────────────────────────────────────\n // ROUTING CONDITIONS\n // Smart conditional routing based on operation mode and missing components\n // ─────────────────────────────────────────────────────────\n\n /**\n * Route from check_state to next step based on operation mode and detected needs.\n */\n const checkStateCondition = (state: typeof EnrichmentGraphState.State): string => {\n // Query mode: Return immediately (fast path)\n if (state.operationMode === 'query') {\n logger.verbose(\"Query mode - ending (fast path)\");\n return END;\n }\n\n // Generate mode: use enrichUserProfile Chat API to auto-generate\n if (state.operationMode === 'generate') {\n logger.verbose(\"Generate mode - routing to auto_generate\");\n return \"auto_generate\";\n }\n\n // Check if user information is insufficient for scraping\n // Return early so chat graph can request the missing information\n if (state.needsUserInfo) {\n logger.verbose(\"⚠️ Insufficient user info - requesting from user\", {\n missingInfo: state.missingUserInfo\n });\n return END;\n }\n\n // Write mode: Check what needs generation\n if (state.needsProfileGeneration) {\n // Only use provided input if it's meaningful (not just \"Yes\" / confirmation)\n if (state.input && isMeaningfulProfileInput(state.input)) {\n // Route through premise decomposition when a premise graph is available.\n // The decompose node extracts atomic premises and creates them; premise\n // events drive user_context regeneration. Without a premise graph there\n // is nothing to do, so end the run.\n if (this.premiseGraph) {\n logger.verbose(\"Profile generation needed — decomposing input into premises\");\n return \"decompose_premises\";\n }\n logger.verbose(\"Profile generation needed but no premise graph injected — ending\");\n return END;\n } else {\n logger.verbose(\"Profile generation needed - scraping first (no meaningful input)\");\n return \"scrape\";\n }\n }\n\n // Everything exists and is up to date\n logger.verbose(\"All components exist - ending\");\n return END;\n };\n\n\n // ─────────────────────────────────────────────────────────\n // GRAPH ASSEMBLY\n // Conditional flow based on operation mode and detected needs\n // ─────────────────────────────────────────────────────────\n\n const workflow = new StateGraph(EnrichmentGraphState)\n // Add all nodes\n .addNode(\"check_state\", checkStateNode)\n .addNode(\"scrape\", scrapeNode)\n .addNode(\"decompose_premises\", decomposePremisesNode)\n .addNode(\"auto_generate\", autoGenerateNode)\n\n // Start with state check\n .addEdge(START, \"check_state\")\n\n // Conditional routing from check_state\n .addConditionalEdges(\n \"check_state\",\n checkStateCondition,\n {\n auto_generate: \"auto_generate\", // Generate mode -> Chat API enrichment\n decompose_premises: \"decompose_premises\", // Write mode + input + premise graph -> decompose\n scrape: \"scrape\", // Need premises, no input -> scrape first\n [END]: END // Query mode, no premise graph, or everything exists\n }\n )\n\n // Decompose premises creates premises as a side effect, then ends.\n // user_context regeneration is handled downstream by premise lifecycle events.\n .addEdge(\"decompose_premises\", END)\n\n // Auto-generate routes to premise decomposition (when premise graph\n // available + enrichment produced input), otherwise ends.\n .addConditionalEdges(\n \"auto_generate\",\n (state: typeof EnrichmentGraphState.State) => {\n if (state.input && this.premiseGraph) {\n logger.verbose(\"Enrichment produced input — routing to premise decomposition\");\n return \"decompose_premises\";\n }\n logger.verbose(\"Enrichment ended without usable input (ghost soft-deleted, error, or no premise graph) — done\");\n return END;\n },\n {\n decompose_premises: \"decompose_premises\",\n [END]: END,\n }\n )\n\n // Scrape -> decompose_premises (when premise graph available), else ends.\n .addConditionalEdges(\n \"scrape\",\n (_state: typeof EnrichmentGraphState.State) => {\n if (this.premiseGraph) return \"decompose_premises\";\n return END;\n },\n {\n decompose_premises: \"decompose_premises\",\n [END]: END,\n },\n );\n\n logger.verbose(\"Graph built successfully\");\n return workflow.compile();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"enrichment.graph.js","sourceRoot":"/","sources":["enrichment/enrichment.graph.ts"],"names":[],"mappings":"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","sourcesContent":["import { StateGraph, START, END } from \"@langchain/langgraph\";\nimport { EnrichmentGraphState } from \"./enrichment.state.js\";\nimport { EnrichmentGraphDatabase, PremiseProvenance } from \"../shared/interfaces/database.interface.js\";\nimport { Scraper } from \"../shared/interfaces/scraper.interface.js\";\nimport type { ProfileEnricher } from \"../shared/interfaces/enrichment.interface.js\";\nimport { shouldEnrichGhostDisplayNameFromParallel, isEnrichedNameMeaningful } from \"./enrichment.enricher.js\";\nimport { socialsToEnrichmentRequest } from \"../shared/utils/social-label.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport type { QuestionerEnqueueFn } from \"../questioner/questioner.types.js\";\nimport { timed } from \"../shared/observability/performance.js\";\nimport { requestContext } from \"../shared/observability/request-context.js\";\nimport type { DebugMetaAgent } from \"../chat/chat-streaming.types.js\";\nimport { PremiseDecomposer } from \"../premise/premise.decomposer.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\n/**\n * Compiled premise graph interface. Matches the invoke signature of a compiled LangGraph.\n * Accepted as an optional dependency so write-mode input can be decomposed into premises.\n */\nexport interface CompiledPremiseGraph {\n invoke(input: {\n userId: string;\n assertionText: string;\n tier: 'assertive' | 'contextual';\n operationMode: 'create';\n /** Volatile premises auto-retract once their validity window lapses. */\n volatile?: boolean;\n /** ISO timestamp after which a contextual premise is no longer valid. */\n validUntil?: string;\n provenanceSource?: PremiseProvenance['source'];\n provenanceSourceId?: string;\n }): Promise<{\n premise?: { id: string } | undefined;\n /** Set when the create was skipped because a near-duplicate already exists. */\n duplicateOf?: { premiseId: string; assertionText: string; similarity: number } | undefined;\n error?: string | undefined;\n }>;\n}\n\nconst logger = protocolLogger(\"EnrichmentGraphFactory\");\n\n/** Minimum length for input to be considered meaningful (e.g. not just \"Yes\") */\nconst MIN_MEANINGFUL_INPUT_LENGTH = 20;\n\n/** Phrases that are confirmations only and must not be used as profile content */\nconst CONFIRMATION_PHRASES = new Set([\n \"yes\", \"yeah\", \"yep\", \"sure\", \"ok\", \"okay\", \"go ahead\", \"do it\", \"please\",\n \"correct\", \"right\", \"exactly\", \"absolutely\", \"of course\", \"sounds good\",\n \"create one\", \"create it\", \"set one up\", \"set it up\", \"create my profile\",\n \"create profile\", \"set up profile\", \"create a profile\"\n]);\n\n/**\n * Returns true only if the input contains real profile information.\n * Confirmation-only replies (e.g. \"Yes\" to \"Would you like to create a profile?\")\n * must not be treated as input so we ask for user info / use scraper instead of inventing a profile.\n */\nfunction isMeaningfulProfileInput(input: string | undefined): boolean {\n if (!input || typeof input !== \"string\") return false;\n const trimmed = input.trim();\n if (trimmed.length < MIN_MEANINGFUL_INPUT_LENGTH) return false;\n const lower = trimmed.toLowerCase();\n if (CONFIRMATION_PHRASES.has(lower)) return false;\n if (CONFIRMATION_PHRASES.has(lower.replace(/[.!?]+$/, \"\"))) return false;\n return true;\n}\n\n\n/**\n * Factory class to build and compile the Profile Generation Graph.\n *\n * Flow:\n * 1. check_state - Detect whether profile needs generation\n * 2. Conditional routing based on operation mode and missing components:\n * - Query mode: Return immediately (fast path)\n * - Write mode: Generate only what's needed\n * 3. Profile generation (if needed)\n * 4. Save profile to DB\n *\n * Key Features:\n * - Read/Write separation (query vs write)\n * - Conditional generation (skip generation if profile already exists)\n */\nexport class EnrichmentGraphFactory {\n constructor(\n private database: EnrichmentGraphDatabase,\n private scraper: Scraper,\n private enricher?: ProfileEnricher,\n private questionerEnqueue?: QuestionerEnqueueFn,\n private premiseGraph?: CompiledPremiseGraph,\n ) { }\n\n public createGraph() {\n const premiseDecomposer = new PremiseDecomposer();\n\n // ─────────────────────────────────────────────────────────\n // NODE: Check State\n // Loads existing profile from DB and detects what needs generation:\n // - Profile missing\n // - User information insufficient for scraping\n // ─────────────────────────────────────────────────────────\n const checkStateNode = async (state: typeof EnrichmentGraphState.State) => {\n return timed(\"ProfileGraph.checkState\", async () => {\n if (!state.userId) {\n logger.error(\"Missing userId\");\n return {\n error: \"userId is required\"\n };\n }\n\n logger.verbose(\"Checking profile state...\", {\n userId: state.userId,\n operationMode: state.operationMode,\n forceUpdate: state.forceUpdate\n });\n\n try {\n const profile = await this.database.getProfile(state.userId) as any;\n // \"Has a profile\" now means the user has been enriched into ACTIVE premises\n // (the user_profiles replacement). `getProfile` returns a users-sourced row\n // for every existing user, so its presence no longer signals enrichment --\n // the premise graph is the source of truth for whether generation has run.\n const hasBeenEnriched = (await this.database.getPremisesForUser(state.userId, 'ACTIVE')).length > 0;\n\n // Query mode: Just return the profile (fast path)\n if (state.operationMode === 'query') {\n logger.verbose(\"🚀 Query mode - returning existing profile (fast path)\", {\n hasProfile: hasBeenEnriched\n });\n const profileWithId = hasBeenEnriched ? await this.database.getProfileByUserId(state.userId) : null;\n return {\n profile: hasBeenEnriched ? (profile || undefined) : undefined,\n readResult: hasBeenEnriched\n ? {\n hasProfile: true,\n // Thin identity only. The structured skills/interests attributes are\n // retired (user_profiles removal, WS6); the rich identity text now\n // comes from the global user_context, injected by read_user_contexts.\n profile: {\n id: profileWithId?.id,\n name: profile?.identity?.name,\n bio: profile?.identity?.bio,\n location: profile?.identity?.location,\n },\n }\n : {\n hasProfile: false,\n message:\n \"You don't have a profile yet. Would you like to create one? You can share your LinkedIn, GitHub, or X/Twitter profile, or just tell me about yourself.\",\n },\n };\n }\n\n // Write mode: Detect what needs generation\n // Treat confirmation-only input (e.g. \"Yes\") as no input so we ask for info / use scraper\n const hasMeaningfulInput = !!state.input && isMeaningfulProfileInput(state.input);\n const needsProfileGeneration = !hasBeenEnriched || (state.forceUpdate && hasMeaningfulInput);\n\n // Check if we need to scrape (profile generation needed but no meaningful input provided)\n const willNeedScraping = needsProfileGeneration && !hasMeaningfulInput;\n\n // If we need to scrape, check if we have sufficient user information\n let needsUserInfo = false;\n const missingUserInfo: string[] = [];\n\n if (willNeedScraping) {\n logger.verbose(\"Will need scraping - checking user information...\");\n\n const user = await this.database.getUser(state.userId);\n\n if (!user) {\n logger.error(\"User not found\", { userId: state.userId });\n return {\n error: `User not found: ${state.userId}`\n };\n }\n\n // Check what information we have from the user table (schema: users)\n // Required fields: email, name (always present)\n // Optional fields: intro, avatar, location, socials\n\n const socials = await this.database.getUserSocials(state.userId);\n const hasSocials = socials.length > 0;\n\n // Check if name is a full name (not just email username)\n // For scraping to work well, we need first + last name\n const hasMeaningfulName = user.name &&\n user.name.trim() !== '' &&\n !user.name.includes('@') &&\n user.name.split(/\\s+/).filter(Boolean).length >= 2;\n\n const hasLocation = !!(user.location && user.location.trim() !== '');\n\n // Minimum requirement for accurate scraping:\n // - At least ONE social link (preferred - most reliable for finding the right person)\n // - OR a full name (first + last) - less reliable but workable\n // Location helps disambiguate but is not required\n\n const hasMinimumInfo = hasSocials || hasMeaningfulName;\n\n if (!hasMinimumInfo) {\n needsUserInfo = true;\n\n // Build precise list of what's missing and would help\n if (!hasSocials) {\n missingUserInfo.push('social_urls');\n }\n if (!hasMeaningfulName) {\n missingUserInfo.push('full_name');\n }\n if (!hasLocation) {\n missingUserInfo.push('location'); // Nice to have\n }\n\n logger.verbose(\"⚠️ Insufficient user information for scraping\", {\n hasSocials,\n hasMeaningfulName,\n hasLocation,\n currentName: user.name,\n missingUserInfo\n });\n } else {\n logger.verbose(\"✅ Sufficient user information for scraping\", {\n hasSocials,\n hasMeaningfulName,\n hasLocation,\n willProceedWith: hasSocials ? 'social links' : 'full name'\n });\n }\n }\n\n logger.verbose(\"📊 State detection complete\", {\n hasProfile: hasBeenEnriched,\n needsProfileGeneration,\n needsUserInfo,\n missingUserInfo,\n forceUpdate: state.forceUpdate,\n hasInput: !!state.input,\n hasMeaningfulInput,\n });\n\n return {\n // Only treat the (users-sourced) profile as existing state when the user has\n // actually been enriched; un-enriched users keep `undefined` so the generate\n // path runs from scratch rather than merging into an empty users row.\n profile: hasBeenEnriched ? (profile || undefined) : undefined,\n needsProfileGeneration,\n needsUserInfo,\n missingUserInfo\n };\n } catch (error) {\n logger.error(\"Failed to load profile\", {\n error: error instanceof Error ? error.message : String(error)\n });\n return {\n profile: undefined,\n error: `Failed to load profile from database: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n });\n };\n\n // ─────────────────────────────────────────────────────────\n // NODE: Scrape\n // Scrapes data from web if input is not provided\n // ─────────────────────────────────────────────────────────\n const scrapeNode = async (state: typeof EnrichmentGraphState.State) => {\n return timed(\"ProfileGraph.scrape\", async () => {\n if (state.input && isMeaningfulProfileInput(state.input)) {\n logger.verbose(\"Meaningful input already provided - skipping scrape\");\n return {};\n }\n\n logger.verbose(\"Starting web scrape...\", {\n userId: state.userId\n });\n\n try {\n // Fetch user details to construct objective for web scraping\n const user = await this.database.getUser(state.userId);\n\n if (!user) {\n logger.error(\"User not found\", { userId: state.userId });\n return {\n error: `User not found: ${state.userId}`\n };\n }\n\n // Build scraping objective from available user information\n // Priority: social links (most reliable) > name + location > email\n const socialParts: string[] = [];\n const socials = await this.database.getUserSocials(state.userId);\n for (const s of socials) {\n switch (s.label) {\n case 'twitter': socialParts.push(`X/Twitter: ${s.value}`); break;\n case 'linkedin': socialParts.push(`LinkedIn: ${s.value}`); break;\n case 'github': socialParts.push(`GitHub: ${s.value}`); break;\n case 'telegram': socialParts.push(`Telegram: ${s.value}`); break;\n default: socialParts.push(`Website: ${s.value}`); break;\n }\n }\n\n // Construct objective based on what we have\n let objective = `Find information about ${user.name || 'this person'}`;\n\n if (user.location) {\n objective += ` located in ${user.location}`;\n }\n\n objective += '.\\n\\n';\n\n if (socialParts.length > 0) {\n objective += `Their social profiles:\\n${socialParts.join('\\n')}\\n\\n`;\n objective += 'Use these links to find accurate information about their professional background, skills, and interests.';\n } else if (user.email) {\n objective += `Their email: ${user.email}\\n\\n`;\n objective += 'Search for professional information, skills, and background about this person.';\n } else {\n objective += 'Search for professional information and background about this person.';\n }\n\n logger.verbose(\"Constructed scraping objective\", {\n hasSocials: socialParts.length > 0,\n hasLocation: !!user.location,\n objectivePreview: objective.substring(0, 100)\n });\n\n const scrapedData = await this.scraper.scrape(objective);\n\n logger.verbose(\"✅ Scrape complete\", {\n dataLength: scrapedData?.length || 0\n });\n\n return {\n objective,\n input: scrapedData,\n activeSocialIds: socials.map(s => s.id),\n operationsPerformed: { scraped: true }\n };\n } catch (error) {\n logger.error(\"Scrape failed\", {\n error: error instanceof Error ? error.message : String(error)\n });\n return {\n error: `Web scrape failed: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n });\n };\n\n // ─────────────────────────────────────────────────────────\n // NODE: Auto-Generate (Parallel Chat API enrichment)\n // Calls enrichUserProfile to get structured data, then builds a\n // text blob as input for the decompose → aggregate → generate\n // pipeline. This ensures enriched users get premises with\n // embeddings, making them discoverable via premise-to-premise\n // matching.\n // On failure, falls back to basic user info for LLM generation.\n // Used in 'generate' mode only.\n // ─────────────────────────────────────────────────────────\n const autoGenerateNode = async (state: typeof EnrichmentGraphState.State) => {\n return timed(\"ProfileGraph.autoGenerate\", async () => {\n logger.verbose(\"Starting auto-generate via Chat API enrichment\", {\n userId: state.userId,\n });\n\n try {\n const user = await this.database.getUser(state.userId);\n if (!user) {\n logger.error(\"User not found for auto-generate\", { userId: state.userId });\n return { error: `User not found: ${state.userId}` };\n }\n\n const socials = await this.database.getUserSocials(state.userId);\n const enrichmentSocials = socialsToEnrichmentRequest(socials);\n const request = {\n name: user.name || undefined,\n email: user.email || undefined,\n linkedin: enrichmentSocials.linkedin || undefined,\n twitter: enrichmentSocials.twitter || undefined,\n github: enrichmentSocials.github || undefined,\n telegram: enrichmentSocials.telegram || undefined,\n websites: enrichmentSocials.websites?.length ? enrichmentSocials.websites : undefined,\n };\n\n const buildBasicInfo = () => {\n const parts = [\n user.name ? `Name: ${user.name}` : '',\n user.email ? `Email: ${user.email}` : '',\n user.location ? `Location: ${user.location}` : '',\n user.intro ? `Bio: ${user.intro}` : '',\n ].filter(Boolean).join('\\n');\n return parts || \"No information available\";\n };\n\n if (!this.enricher) {\n logger.warn(\"No enricher configured — falling back to basic info\", { userId: state.userId });\n return {\n input: buildBasicInfo(),\n needsUserInfo: false,\n needsProfileGeneration: true,\n operationsPerformed: { scraped: true },\n };\n }\n\n try {\n const enrichment = await this.enricher.enrichUserProfile(request);\n\n if (enrichment && !enrichment.isHuman) {\n logger.info(\"Enrichment detected non-human entity, soft-deleting ghost\", { userId: state.userId });\n await this.database.softDeleteGhost(state.userId);\n return { error: \"Non-human entity detected\" };\n }\n\n const hasMeaningfulEnrichment = !!enrichment &&\n enrichment.confidentMatch &&\n (\n enrichment.identity.bio.trim().length > 0 ||\n enrichment.narrative.context.trim().length > 0 ||\n enrichment.attributes.skills.length > 0 ||\n enrichment.attributes.interests.length > 0\n );\n\n if (hasMeaningfulEnrichment) {\n if (user.isGhost && !isEnrichedNameMeaningful(user.email || '', enrichment!.identity.name || '')) {\n logger.info(\"Enrichment has content but no real name for ghost, soft-deleting\", { userId: state.userId });\n await this.database.softDeleteGhost(state.userId);\n return { error: \"No real name found for ghost user\" };\n }\n\n logger.verbose(\"Chat API enrichment succeeded\", {\n userId: state.userId,\n skillsCount: enrichment!.attributes.skills.length,\n interestsCount: enrichment!.attributes.interests.length,\n });\n\n // Update user record with enriched data\n const updatePayload: {\n name?: string;\n intro?: string;\n location?: string;\n } = {};\n const enrichedName = enrichment!.identity.name?.trim();\n if (\n enrichedName &&\n shouldEnrichGhostDisplayNameFromParallel(\n { isGhost: !!user.isGhost, name: user.name ?? '', email: user.email ?? '' },\n enrichedName,\n )\n ) {\n updatePayload.name = enrichedName;\n }\n if (enrichment!.identity.bio?.trim()) updatePayload.intro = enrichment!.identity.bio.trim();\n if (enrichment!.identity.location?.trim()) updatePayload.location = enrichment!.identity.location.trim();\n\n const enrichedSocials: { label: string; value: string }[] = [];\n if (enrichment!.socials.twitter) enrichedSocials.push({ label: 'twitter', value: enrichment!.socials.twitter });\n if (enrichment!.socials.linkedin) enrichedSocials.push({ label: 'linkedin', value: enrichment!.socials.linkedin });\n if (enrichment!.socials.github) enrichedSocials.push({ label: 'github', value: enrichment!.socials.github });\n if (enrichment!.socials.telegram) enrichedSocials.push({ label: 'telegram', value: enrichment!.socials.telegram });\n if (enrichment!.socials.websites?.length) {\n for (const w of enrichment!.socials.websites) enrichedSocials.push({ label: 'custom', value: w });\n }\n if (enrichedSocials.length > 0) {\n const existingSocials = await this.database.getUserSocials(state.userId);\n const enrichedLabels = new Set(enrichedSocials.map(s => s.label));\n const kept = existingSocials\n .filter(s => !enrichedLabels.has(s.label) || s.label === 'custom')\n .map(s => ({ label: s.label, value: s.value }));\n const merged = enrichedLabels.has('custom')\n ? [...kept.filter(s => s.label !== 'custom'), ...enrichedSocials]\n : [...kept, ...enrichedSocials];\n await this.database.setUserSocials(state.userId, merged);\n }\n\n if (Object.keys(updatePayload).length > 0) {\n await this.database.updateUser(state.userId, updatePayload);\n }\n\n // Post-enrichment dedup: check if this ghost matches an existing user\n if (user.isGhost) {\n const currentSocials = await this.database.getUserSocials(state.userId);\n const duplicate = await this.database.findDuplicateUser(state.userId, currentSocials);\n if (duplicate) {\n logger.info(\"Post-enrichment dedup: merging ghost into existing user\", {\n ghostId: state.userId,\n targetId: duplicate.id,\n });\n await this.database.mergeGhostUser(state.userId, duplicate.id);\n return { error: `Merged as duplicate of user ${duplicate.id}` };\n }\n }\n\n // Build a text blob from the enrichment result so it flows\n // through premise decomposition (when available) rather than\n // bypassing premises via prePopulatedProfile.\n const enrichmentParts = [\n enrichment!.identity.name ? `My name is ${enrichment!.identity.name}.` : '',\n enrichment!.identity.location ? `I am based in ${enrichment!.identity.location}.` : '',\n enrichment!.identity.bio || '',\n enrichment!.narrative.context || '',\n enrichment!.attributes.skills.length ? `My skills include ${enrichment!.attributes.skills.join(', ')}.` : '',\n enrichment!.attributes.interests.length ? `My interests include ${enrichment!.attributes.interests.join(', ')}.` : '',\n ].filter(Boolean).join('\\n');\n\n return {\n input: enrichmentParts,\n needsUserInfo: false,\n needsProfileGeneration: true,\n forceUpdate: true,\n activeSocialIds: socials.map(s => s.id),\n operationsPerformed: { scraped: true },\n };\n }\n\n if (user.isGhost) {\n logger.info(\"Low-confidence enrichment for ghost, soft-deleting\", { userId: state.userId });\n await this.database.softDeleteGhost(state.userId);\n return { error: \"Enrichment not confident for ghost user\" };\n }\n logger.warn(\"Chat API returned low-signal enrichment, falling back to basic info\", { userId: state.userId });\n } catch (enrichErr) {\n if (user.isGhost) {\n logger.info(\"Enrichment failed for ghost, soft-deleting\", { userId: state.userId });\n await this.database.softDeleteGhost(state.userId);\n return { error: \"Enrichment failed for ghost user\" };\n }\n logger.warn(\"Chat API enrichment failed, falling back to basic info\", {\n userId: state.userId,\n error: enrichErr instanceof Error ? enrichErr.message : String(enrichErr),\n });\n }\n\n return {\n input: buildBasicInfo(),\n needsUserInfo: false,\n needsProfileGeneration: true,\n operationsPerformed: { scraped: true },\n };\n } catch (err) {\n logger.error(\"Auto-generate failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return { error: `Auto-generate failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n });\n };\n\n // ─────────────────────────────────────────────────────────\n // NODE: Decompose Premises\n // Decomposes free-text input (chat or scraped) into individual premises\n // and creates each via the premise graph. Premise creation is the terminal\n // effect: premise lifecycle events drive user_context regeneration downstream\n // (the legacy aggregate→generate→save profile tail was removed in WS8/IND-365,\n // along with the user_profiles table it wrote to).\n // ─────────────────────────────────────────────────────────\n const decomposePremisesNode = async (state: typeof EnrichmentGraphState.State) => {\n return timed(\"ProfileGraph.decomposePremises\", async () => {\n if (!state.input) {\n logger.error(\"No input for premise decomposition\");\n return { error: \"Input required for premise decomposition\" };\n }\n\n if (!this.premiseGraph) {\n // No premise graph injected — nothing to decompose into. End the run.\n logger.warn(\"No premise graph injected — skipping premise decomposition\");\n return {};\n }\n\n logger.verbose(\"Decomposing input into premises...\", {\n userId: state.userId,\n inputLength: state.input.length,\n });\n\n const agentTimingsAccum: DebugMetaAgent[] = [];\n\n try {\n const _traceEmitter = requestContext.getStore()?.traceEmitter;\n\n const decomposeStart = Date.now();\n _traceEmitter?.({ type: \"agent_start\", name: \"premise-decomposer\" });\n const result = await premiseDecomposer.invoke(state.input);\n const decomposeMs = Date.now() - decomposeStart;\n agentTimingsAccum.push({ name: \"premise.decomposer\", durationMs: decomposeMs });\n _traceEmitter?.({\n type: \"agent_end\",\n name: \"premise-decomposer\",\n durationMs: decomposeMs,\n summary: `Decomposed into ${result.premises.length} premise(s)`,\n });\n\n if (result.premises.length === 0) {\n logger.verbose(\"No premises extracted — nothing to create\");\n return {\n agentTimings: agentTimingsAccum,\n };\n }\n\n logger.verbose(`Creating ${result.premises.length} premise(s) via premise graph`, {\n userId: state.userId,\n });\n\n let created = 0;\n let skippedDuplicates = 0;\n for (const p of result.premises) {\n try {\n // Contextual premises carry an LLM-inferred validity window and are\n // volatile (auto-retract on expiry); assertive premises do not expire.\n const isContextual = p.tier === 'contextual';\n const validUntil = isContextual && p.validityDays\n ? new Date(Date.now() + p.validityDays * 24 * 60 * 60 * 1000).toISOString()\n : undefined;\n\n const premiseResult = await invokeWithAbortSignal(this.premiseGraph, {\n userId: state.userId,\n assertionText: p.text,\n tier: p.tier,\n operationMode: 'create',\n volatile: isContextual,\n ...(validUntil ? { validUntil } : {}),\n ...(state.activeSocialIds?.length\n ? { provenanceSource: 'integration' as const, provenanceSourceId: state.activeSocialIds[0] }\n : {}),\n });\n\n if (premiseResult.premise) {\n created++;\n } else if (premiseResult.duplicateOf) {\n skippedDuplicates++;\n } else if (premiseResult.error) {\n logger.warn(\"Premise creation failed\", {\n text: p.text.substring(0, 60),\n error: premiseResult.error,\n });\n }\n } catch (err) {\n logger.warn(\"Premise creation threw\", {\n text: p.text.substring(0, 60),\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n logger.verbose(`Created ${created}/${result.premises.length} premise(s) (${skippedDuplicates} skipped as near-duplicates)`, {\n userId: state.userId,\n });\n\n return {\n agentTimings: agentTimingsAccum,\n operationsPerformed: { decomposedPremises: true },\n };\n } catch (err) {\n logger.error(\"Premise decomposition failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return {\n agentTimings: agentTimingsAccum,\n };\n }\n });\n };\n\n // ─────────────────────────────────────────────────────────\n // ROUTING CONDITIONS\n // Smart conditional routing based on operation mode and missing components\n // ─────────────────────────────────────────────────────────\n\n /**\n * Route from check_state to next step based on operation mode and detected needs.\n */\n const checkStateCondition = (state: typeof EnrichmentGraphState.State): string => {\n // Query mode: Return immediately (fast path)\n if (state.operationMode === 'query') {\n logger.verbose(\"Query mode - ending (fast path)\");\n return END;\n }\n\n // Generate mode: use enrichUserProfile Chat API to auto-generate\n if (state.operationMode === 'generate') {\n logger.verbose(\"Generate mode - routing to auto_generate\");\n return \"auto_generate\";\n }\n\n // Check if user information is insufficient for scraping\n // Return early so chat graph can request the missing information\n if (state.needsUserInfo) {\n logger.verbose(\"⚠️ Insufficient user info - requesting from user\", {\n missingInfo: state.missingUserInfo\n });\n return END;\n }\n\n // Write mode: Check what needs generation\n if (state.needsProfileGeneration) {\n // Only use provided input if it's meaningful (not just \"Yes\" / confirmation)\n if (state.input && isMeaningfulProfileInput(state.input)) {\n // Route through premise decomposition when a premise graph is available.\n // The decompose node extracts atomic premises and creates them; premise\n // events drive user_context regeneration. Without a premise graph there\n // is nothing to do, so end the run.\n if (this.premiseGraph) {\n logger.verbose(\"Profile generation needed — decomposing input into premises\");\n return \"decompose_premises\";\n }\n logger.verbose(\"Profile generation needed but no premise graph injected — ending\");\n return END;\n } else {\n logger.verbose(\"Profile generation needed - scraping first (no meaningful input)\");\n return \"scrape\";\n }\n }\n\n // Everything exists and is up to date\n logger.verbose(\"All components exist - ending\");\n return END;\n };\n\n\n // ─────────────────────────────────────────────────────────\n // GRAPH ASSEMBLY\n // Conditional flow based on operation mode and detected needs\n // ─────────────────────────────────────────────────────────\n\n const workflow = new StateGraph(EnrichmentGraphState)\n // Add all nodes\n .addNode(\"check_state\", checkStateNode)\n .addNode(\"scrape\", scrapeNode)\n .addNode(\"decompose_premises\", decomposePremisesNode)\n .addNode(\"auto_generate\", autoGenerateNode)\n\n // Start with state check\n .addEdge(START, \"check_state\")\n\n // Conditional routing from check_state\n .addConditionalEdges(\n \"check_state\",\n checkStateCondition,\n {\n auto_generate: \"auto_generate\", // Generate mode -> Chat API enrichment\n decompose_premises: \"decompose_premises\", // Write mode + input + premise graph -> decompose\n scrape: \"scrape\", // Need premises, no input -> scrape first\n [END]: END // Query mode, no premise graph, or everything exists\n }\n )\n\n // Decompose premises creates premises as a side effect, then ends.\n // user_context regeneration is handled downstream by premise lifecycle events.\n .addEdge(\"decompose_premises\", END)\n\n // Auto-generate routes to premise decomposition (when premise graph\n // available + enrichment produced input), otherwise ends.\n .addConditionalEdges(\n \"auto_generate\",\n (state: typeof EnrichmentGraphState.State) => {\n if (state.input && this.premiseGraph) {\n logger.verbose(\"Enrichment produced input — routing to premise decomposition\");\n return \"decompose_premises\";\n }\n logger.verbose(\"Enrichment ended without usable input (ghost soft-deleted, error, or no premise graph) — done\");\n return END;\n },\n {\n decompose_premises: \"decompose_premises\",\n [END]: END,\n }\n )\n\n // Scrape -> decompose_premises (when premise graph available), else ends.\n .addConditionalEdges(\n \"scrape\",\n (_state: typeof EnrichmentGraphState.State) => {\n if (this.premiseGraph) return \"decompose_premises\";\n return END;\n },\n {\n decompose_premises: \"decompose_premises\",\n [END]: END,\n },\n );\n\n logger.verbose(\"Graph built successfully\");\n return workflow.compile();\n }\n}\n"]}
|