@indexnetwork/protocol 4.3.4-rc.309.1 → 4.3.4-rc.310.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/IMPLEMENTATION.md +2 -2
  2. package/dist/chat/chat.agent.d.ts +1 -1
  3. package/dist/chat/chat.agent.js +1 -1
  4. package/dist/chat/chat.agent.js.map +1 -1
  5. package/dist/chat/chat.prompt.js +30 -30
  6. package/dist/chat/chat.prompt.js.map +1 -1
  7. package/dist/chat/chat.prompt.modules.js +8 -8
  8. package/dist/chat/chat.prompt.modules.js.map +1 -1
  9. package/dist/chat/chat.state.d.ts +1 -1
  10. package/dist/chat/chat.state.d.ts.map +1 -1
  11. package/dist/chat/chat.state.js.map +1 -1
  12. package/dist/chat/tests/chat.graph.mocks.d.ts +1 -1
  13. package/dist/chat/tests/chat.graph.mocks.js +1 -1
  14. package/dist/chat/tests/chat.graph.mocks.js.map +1 -1
  15. package/dist/contact/contact.tools.js +6 -6
  16. package/dist/contact/contact.tools.js.map +1 -1
  17. package/dist/enrichment/enrichment.tools.js +7 -7
  18. package/dist/enrichment/enrichment.tools.js.map +1 -1
  19. package/dist/integration/integration.tools.js +1 -1
  20. package/dist/integration/integration.tools.js.map +1 -1
  21. package/dist/intent/intent.graph.d.ts.map +1 -1
  22. package/dist/intent/intent.graph.js +9 -9
  23. package/dist/intent/intent.graph.js.map +1 -1
  24. package/dist/intent/intent.indexer.d.ts +1 -1
  25. package/dist/intent/intent.indexer.js +4 -4
  26. package/dist/intent/intent.indexer.js.map +1 -1
  27. package/dist/intent/intent.state.d.ts +7 -7
  28. package/dist/intent/intent.state.js +7 -7
  29. package/dist/intent/intent.state.js.map +1 -1
  30. package/dist/intent/intent.tools.js +26 -26
  31. package/dist/intent/intent.tools.js.map +1 -1
  32. package/dist/maintenance/maintenance.graph.d.ts +2 -2
  33. package/dist/maintenance/maintenance.graph.d.ts.map +1 -1
  34. package/dist/maintenance/maintenance.graph.js.map +1 -1
  35. package/dist/mcp/mcp.server.d.ts +2 -2
  36. package/dist/mcp/mcp.server.js +4 -4
  37. package/dist/mcp/mcp.server.js.map +1 -1
  38. package/dist/network/indexer/indexer.graph.d.ts +2 -2
  39. package/dist/network/indexer/indexer.graph.d.ts.map +1 -1
  40. package/dist/network/indexer/indexer.graph.js +13 -13
  41. package/dist/network/indexer/indexer.graph.js.map +1 -1
  42. package/dist/network/indexer/indexer.state.d.ts +3 -3
  43. package/dist/network/indexer/indexer.state.d.ts.map +1 -1
  44. package/dist/network/indexer/indexer.state.js +4 -4
  45. package/dist/network/indexer/indexer.state.js.map +1 -1
  46. package/dist/network/membership/membership.graph.d.ts +1 -1
  47. package/dist/network/membership/membership.graph.js +21 -21
  48. package/dist/network/membership/membership.graph.js.map +1 -1
  49. package/dist/network/membership/membership.state.d.ts +2 -2
  50. package/dist/network/membership/membership.state.js +2 -2
  51. package/dist/network/membership/membership.state.js.map +1 -1
  52. package/dist/network/network.graph.d.ts +1 -1
  53. package/dist/network/network.graph.d.ts.map +1 -1
  54. package/dist/network/network.graph.js +13 -13
  55. package/dist/network/network.graph.js.map +1 -1
  56. package/dist/network/network.state.d.ts +3 -3
  57. package/dist/network/network.state.d.ts.map +1 -1
  58. package/dist/network/network.state.js +3 -3
  59. package/dist/network/network.state.js.map +1 -1
  60. package/dist/network/network.tools.d.ts.map +1 -1
  61. package/dist/network/network.tools.js +95 -107
  62. package/dist/network/network.tools.js.map +1 -1
  63. package/dist/opportunity/opportunity.discover.d.ts +1 -1
  64. package/dist/opportunity/opportunity.discover.d.ts.map +1 -1
  65. package/dist/opportunity/opportunity.discover.js +1 -1
  66. package/dist/opportunity/opportunity.discover.js.map +1 -1
  67. package/dist/opportunity/opportunity.graph.js +10 -10
  68. package/dist/opportunity/opportunity.graph.js.map +1 -1
  69. package/dist/opportunity/opportunity.introducer.d.ts +3 -3
  70. package/dist/opportunity/opportunity.introducer.d.ts.map +1 -1
  71. package/dist/opportunity/opportunity.introducer.js +2 -2
  72. package/dist/opportunity/opportunity.introducer.js.map +1 -1
  73. package/dist/opportunity/opportunity.state.d.ts +1 -1
  74. package/dist/opportunity/opportunity.state.js +1 -1
  75. package/dist/opportunity/opportunity.state.js.map +1 -1
  76. package/dist/opportunity/opportunity.tools.js +18 -18
  77. package/dist/opportunity/opportunity.tools.js.map +1 -1
  78. package/dist/premise/premise.indexer.d.ts +1 -1
  79. package/dist/premise/premise.indexer.js +5 -5
  80. package/dist/premise/premise.indexer.js.map +1 -1
  81. package/dist/questioner/questioner.tools.js +1 -1
  82. package/dist/questioner/questioner.tools.js.map +1 -1
  83. package/dist/shared/agent/tool.factory.d.ts +1 -1
  84. package/dist/shared/agent/tool.factory.js +1 -1
  85. package/dist/shared/agent/tool.factory.js.map +1 -1
  86. package/dist/shared/agent/tool.helpers.d.ts +6 -6
  87. package/dist/shared/agent/tool.helpers.d.ts.map +1 -1
  88. package/dist/shared/agent/tool.helpers.js +2 -2
  89. package/dist/shared/agent/tool.helpers.js.map +1 -1
  90. package/dist/shared/agent/tool.scope.js +1 -1
  91. package/dist/shared/agent/tool.scope.js.map +1 -1
  92. package/dist/shared/agent/utility.tools.js +20 -20
  93. package/dist/shared/agent/utility.tools.js.map +1 -1
  94. package/dist/shared/interfaces/database.interface.d.ts +59 -59
  95. package/dist/shared/interfaces/database.interface.d.ts.map +1 -1
  96. package/dist/shared/interfaces/database.interface.js.map +1 -1
  97. package/dist/shared/interfaces/embedder.interface.d.ts +2 -2
  98. package/dist/shared/interfaces/embedder.interface.d.ts.map +1 -1
  99. package/dist/shared/interfaces/embedder.interface.js.map +1 -1
  100. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"chat.state.js","sourceRoot":"/","sources":["chat/chat.state.ts"],"names":[],"mappings":"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","sourcesContent":["import { Annotation, messagesStateReducer } from \"@langchain/langgraph\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type { DebugMetaToolCall, DebugMetaLlm, DebugMetaOrchestratorNegotiations } from \"./chat-streaming.types.js\";\n\n// ══════════════════════════════════════════════════════════════════════════════\n// TYPES (used by legacy subgraph nodes; agent-loop graph does not set these)\n// ══════════════════════════════════════════════════════════════════════════════\n\n/** Routing decision from router node (target, operationType, extractedContext). */\nexport interface RoutingDecision {\n target: string;\n operationType: string | null;\n extractedContext?: string | null;\n}\n\n/** Intent subgraph result (actions, inferredIntents, etc.). */\nexport interface IntentSubgraphResult {\n actions?: Array<{ type: string; payload?: string }>;\n inferredIntents?: unknown[];\n indexingResults?: unknown[];\n mode?: string;\n intents?: unknown[];\n count?: number;\n error?: string;\n /** When the intent graph exits early (e.g. index-scoped without intents); surface to user. */\n requiredMessage?: string;\n}\n\n/** Index subgraph result (memberships, ownedIndexes, specificIndexData). */\nexport interface IndexSubgraphResult {\n mode?: string;\n memberships?: unknown[];\n ownedIndexes?: unknown[];\n specificIndexData?: unknown;\n count?: number;\n error?: string;\n}\n\n/** Aggregated results from subgraphs (intent, index, profile, opportunity, scrape). */\nexport interface SubgraphResults {\n intent?: IntentSubgraphResult;\n index?: IndexSubgraphResult;\n profile?: unknown;\n opportunity?: unknown;\n scrape?: unknown;\n}\n\n// ══════════════════════════════════════════════════════════════════════════════\n// CHAT GRAPH STATE (Agent Loop Architecture)\n// ══════════════════════════════════════════════════════════════════════════════\n\n/**\n * The Chat Graph State using LangGraph Annotations.\n * \n * This is a simplified state for the agent loop architecture.\n * The agent handles all routing decisions internally via tool calling.\n * \n * Design Principles:\n * - Messages accumulate through the conversation (includes tool calls/results)\n * - Iteration count tracks loop progress for soft/hard limits\n * - Final response is extracted at the end\n */\nexport const ChatGraphState = Annotation.Root({\n // ═══════════════════════════════════════════════════════════════════════════\n // CORE INPUTS\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * The User ID - required for all operations.\n */\n userId: Annotation<string>,\n\n /**\n * Legacy optional index (community) ID when chat is scoped to a specific index.\n * New callers should set scopeType/scopeId; networkId is retained as an edge alias.\n */\n networkId: Annotation<string | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n\n /** Focused request scope type. Currently only `network` exists. */\n scopeType: Annotation<'network' | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n\n /** Focused request scope id. When scopeType is `network`, this is the network id. */\n scopeId: Annotation<string | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n\n /**\n * Chat session ID when streaming with context. Used by tools to create draft\n * opportunities tied to this conversation (context.conversationId).\n */\n sessionId: Annotation<string | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n\n /**\n * Conversation history using LangGraph's built-in message reducer.\n * Includes: HumanMessage, AIMessage, ToolMessage, SystemMessage\n * Automatically handles message appending, ID management, and ordering.\n */\n messages: Annotation<BaseMessage[]>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n\n // ═══════════════════════════════════════════════════════════════════════════\n // LOOP CONTROL\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Current iteration count in the agent loop.\n * Used for soft limit (nudge) and hard limit (force exit).\n */\n iterationCount: Annotation<number>({\n reducer: (curr, next) => next,\n default: () => 0,\n }),\n\n /**\n * Flag indicating whether the agent loop should continue.\n * Set to false when agent produces final response or hits hard limit.\n */\n shouldContinue: Annotation<boolean>({\n reducer: (curr, next) => next,\n default: () => true,\n }),\n\n // ═══════════════════════════════════════════════════════════════════════════\n // OUTPUTS\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * The final generated response text.\n * Set when the agent decides to stop and respond.\n */\n responseText: Annotation<string | undefined>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n\n /**\n * Error message if the agent loop fails.\n */\n error: Annotation<string | undefined>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n\n /**\n * Per-turn debug meta (graph, iterations, tool calls) for copy-debug.\n * Not persisted; only used so the streamer receives it in the updates chunk.\n */\n debugMeta: Annotation<{ graph: string; iterations: number; tools: DebugMetaToolCall[]; llm: DebugMetaLlm; orchestratorNegotiations?: DebugMetaOrchestratorNegotiations } | undefined>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n\n // Legacy subgraph state (used by index/intent/response nodes when present)\n /** Router output: target, operationType, extractedContext. */\n routingDecision: Annotation<RoutingDecision | undefined>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n /** Results from intent/profile/opportunity/scrape subgraphs. */\n subgraphResults: Annotation<SubgraphResults | undefined>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n /** User profile context (e.g. for intent nodes). */\n userProfile: Annotation<unknown>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n\n});\n\n// ══════════════════════════════════════════════════════════════════════════════\n// TYPE EXPORTS\n// ══════════════════════════════════════════════════════════════════════════════\n\n/**\n * The full state type for the Chat Graph.\n * Use this for typing node functions and graph invocations.\n */\nexport type ChatGraphStateType = typeof ChatGraphState.State;\n"]}
1
+ {"version":3,"file":"chat.state.js","sourceRoot":"/","sources":["chat/chat.state.ts"],"names":[],"mappings":"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","sourcesContent":["import { Annotation, messagesStateReducer } from \"@langchain/langgraph\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\n\nimport type { DebugMetaToolCall, DebugMetaLlm, DebugMetaOrchestratorNegotiations } from \"./chat-streaming.types.js\";\n\n// ══════════════════════════════════════════════════════════════════════════════\n// TYPES (used by legacy subgraph nodes; agent-loop graph does not set these)\n// ══════════════════════════════════════════════════════════════════════════════\n\n/** Routing decision from router node (target, operationType, extractedContext). */\nexport interface RoutingDecision {\n target: string;\n operationType: string | null;\n extractedContext?: string | null;\n}\n\n/** Intent subgraph result (actions, inferredIntents, etc.). */\nexport interface IntentSubgraphResult {\n actions?: Array<{ type: string; payload?: string }>;\n inferredIntents?: unknown[];\n indexingResults?: unknown[];\n mode?: string;\n intents?: unknown[];\n count?: number;\n error?: string;\n /** When the intent graph exits early (e.g. network-scoped without intents); surface to user. */\n requiredMessage?: string;\n}\n\n/** Index subgraph result (memberships, ownedIndexes, specificIndexData). */\nexport interface IndexSubgraphResult {\n mode?: string;\n memberships?: unknown[];\n ownedIndexes?: unknown[];\n specificIndexData?: unknown;\n count?: number;\n error?: string;\n}\n\n/** Aggregated results from subgraphs (intent, index, profile, opportunity, scrape). */\nexport interface SubgraphResults {\n intent?: IntentSubgraphResult;\n index?: IndexSubgraphResult;\n profile?: unknown;\n opportunity?: unknown;\n scrape?: unknown;\n}\n\n// ══════════════════════════════════════════════════════════════════════════════\n// CHAT GRAPH STATE (Agent Loop Architecture)\n// ══════════════════════════════════════════════════════════════════════════════\n\n/**\n * The Chat Graph State using LangGraph Annotations.\n * \n * This is a simplified state for the agent loop architecture.\n * The agent handles all routing decisions internally via tool calling.\n * \n * Design Principles:\n * - Messages accumulate through the conversation (includes tool calls/results)\n * - Iteration count tracks loop progress for soft/hard limits\n * - Final response is extracted at the end\n */\nexport const ChatGraphState = Annotation.Root({\n // ═══════════════════════════════════════════════════════════════════════════\n // CORE INPUTS\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * The User ID - required for all operations.\n */\n userId: Annotation<string>,\n\n /**\n * Legacy optional index (community) ID when chat is scoped to a specific index.\n * New callers should set scopeType/scopeId; networkId is retained as an edge alias.\n */\n networkId: Annotation<string | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n\n /** Focused request scope type. Currently only `network` exists. */\n scopeType: Annotation<'network' | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n\n /** Focused request scope id. When scopeType is `network`, this is the network id. */\n scopeId: Annotation<string | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n\n /**\n * Chat session ID when streaming with context. Used by tools to create draft\n * opportunities tied to this conversation (context.conversationId).\n */\n sessionId: Annotation<string | undefined>({\n reducer: (curr, next) => next ?? curr,\n default: () => undefined,\n }),\n\n /**\n * Conversation history using LangGraph's built-in message reducer.\n * Includes: HumanMessage, AIMessage, ToolMessage, SystemMessage\n * Automatically handles message appending, ID management, and ordering.\n */\n messages: Annotation<BaseMessage[]>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n\n // ═══════════════════════════════════════════════════════════════════════════\n // LOOP CONTROL\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Current iteration count in the agent loop.\n * Used for soft limit (nudge) and hard limit (force exit).\n */\n iterationCount: Annotation<number>({\n reducer: (curr, next) => next,\n default: () => 0,\n }),\n\n /**\n * Flag indicating whether the agent loop should continue.\n * Set to false when agent produces final response or hits hard limit.\n */\n shouldContinue: Annotation<boolean>({\n reducer: (curr, next) => next,\n default: () => true,\n }),\n\n // ═══════════════════════════════════════════════════════════════════════════\n // OUTPUTS\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * The final generated response text.\n * Set when the agent decides to stop and respond.\n */\n responseText: Annotation<string | undefined>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n\n /**\n * Error message if the agent loop fails.\n */\n error: Annotation<string | undefined>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n\n /**\n * Per-turn debug meta (graph, iterations, tool calls) for copy-debug.\n * Not persisted; only used so the streamer receives it in the updates chunk.\n */\n debugMeta: Annotation<{ graph: string; iterations: number; tools: DebugMetaToolCall[]; llm: DebugMetaLlm; orchestratorNegotiations?: DebugMetaOrchestratorNegotiations } | undefined>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n\n // Legacy subgraph state (used by index/intent/response nodes when present)\n /** Router output: target, operationType, extractedContext. */\n routingDecision: Annotation<RoutingDecision | undefined>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n /** Results from intent/profile/opportunity/scrape subgraphs. */\n subgraphResults: Annotation<SubgraphResults | undefined>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n /** User profile context (e.g. for intent nodes). */\n userProfile: Annotation<unknown>({\n reducer: (curr, next) => next,\n default: () => undefined,\n }),\n\n});\n\n// ══════════════════════════════════════════════════════════════════════════════\n// TYPE EXPORTS\n// ══════════════════════════════════════════════════════════════════════════════\n\n/**\n * The full state type for the Chat Graph.\n * Use this for typing node functions and graph invocations.\n */\nexport type ChatGraphStateType = typeof ChatGraphState.State;\n"]}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Configurable mock database and fixture data for chat graph workflow tests.
3
3
  * Use createChatGraphMockDb(config) to get a full ChatGraphCompositeDatabase
4
- * with controllable profile, intents, index membership, and opportunities.
4
+ * with controllable profile, intents, network membership, and opportunities.
5
5
  */
6
6
  import type { ChatGraphCompositeDatabase, ActiveIntent, IndexedIntentDetails, NetworkMembership, OwnedIndex, UserRecord, Opportunity, OpportunityStatus } from "../../shared/interfaces/database.interface.js";
7
7
  import type { ChatSessionReader } from "../../shared/interfaces/chat-session.interface.js";
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Configurable mock database and fixture data for chat graph workflow tests.
3
3
  * Use createChatGraphMockDb(config) to get a full ChatGraphCompositeDatabase
4
- * with controllable profile, intents, index membership, and opportunities.
4
+ * with controllable profile, intents, network membership, and opportunities.
5
5
  */
6
6
  const noop = async () => undefined;
7
7
  const noopArray = async () => [];
@@ -1 +1 @@
1
- {"version":3,"file":"chat.graph.mocks.js","sourceRoot":"/","sources":["chat/tests/chat.graph.mocks.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Configurable mock database and fixture data for chat graph workflow tests.\n * Use createChatGraphMockDb(config) to get a full ChatGraphCompositeDatabase\n * with controllable profile, intents, index membership, and opportunities.\n */\n\nimport type { ChatGraphCompositeDatabase, CreateIntentData, ActiveIntent, IndexedIntentDetails, NetworkMembership, OwnedIndex, UserRecord, Opportunity, OpportunityStatus } from \"../../shared/interfaces/database.interface.js\";\nimport type { ChatSessionReader } from \"../../shared/interfaces/chat-session.interface.js\";\nimport type { ProtocolDeps } from \"../../shared/agent/tool.helpers.js\";\n\n// Minimal profile shape for getProfileByUserId (UserIdentity-shaped: identity + context)\nexport interface MockProfileFixture {\n id: string;\n userId: string;\n identity: { name: string; bio: string; location: string };\n context: string;\n embedding: number[] | null;\n}\n\nexport interface ChatGraphMockConfig {\n /** Profile for the session user (null = no profile). */\n profile?: MockProfileFixture | null;\n /** Active intents per userId (global scope). */\n activeIntents?: (userId: string) => ActiveIntent[] | Promise<ActiveIntent[]>;\n /** Intents in index for a member (userId, networkId) -> member's intents in that index. */\n intentsInIndexForMember?: (\n userId: string,\n networkId: string\n ) => ActiveIntent[] | Promise<ActiveIntent[]>;\n /** All intents in index (owner view). (networkId, requestingUserId) -> details. */\n indexIntentsForOwner?: (\n networkId: string,\n requestingUserId: string\n ) => IndexedIntentDetails[] | Promise<IndexedIntentDetails[]>;\n /** Opportunities for user. */\n opportunitiesForUser?: (userId: string) => Opportunity[] | Promise<Opportunity[]>;\n /** Network memberships for user. */\n networkMemberships?: (userId: string) => NetworkMembership[] | Promise<NetworkMembership[]>;\n /** Index by id (for scope validation). */\n getNetwork?: (networkId: string) => { id: string; title: string } | null | Promise<{ id: string; title: string } | null>;\n /** (networkId, userId) -> is member. */\n isNetworkMember?: (networkId: string, userId: string) => boolean | Promise<boolean>;\n /** (networkId, userId) -> is owner. */\n isIndexOwner?: (networkId: string, userId: string) => boolean | Promise<boolean>;\n /** User record by id. */\n getUser?: (userId: string) => UserRecord | null | Promise<UserRecord | null>;\n /** Owned indexes for user. */\n ownedIndexes?: (userId: string) => OwnedIndex[] | Promise<OwnedIndex[]>;\n}\n\nconst noop = async (): Promise<undefined> => undefined;\nconst noopArray = async <T>(): Promise<T[]> => [];\nconst noopNull = async (): Promise<null> => null;\nconst noopBool = async (): Promise<boolean> => false;\n\nconst defaultOwnedIndex = (): OwnedIndex => ({\n id: \"\",\n title: \"\",\n prompt: null,\n imageUrl: null,\n permissions: {\n joinPolicy: \"anyone\",\n allowGuestVibeCheck: false,\n invitationLink: null,\n },\n isPersonal: false,\n createdAt: new Date(),\n updatedAt: new Date(),\n memberCount: 0,\n intentCount: 0,\n user: { id: \"\", name: \"\", avatar: null },\n _count: { members: 0 },\n});\n\n/** Actor shape for opportunity mocks (role determines visibility). */\nexport type MockOpportunityActor = { networkId: string; userId: string; role: \"introducer\" | \"patient\" | \"agent\" | \"peer\" | \"party\"; intent?: string };\n\n/** Build a minimal Opportunity for list_opportunities / discover_opportunities tests. */\nexport function mockOpportunity(overrides: {\n id?: string;\n status?: OpportunityStatus;\n networkId?: string;\n /** Current user (must be one of the actors so they \"have\" this opportunity). */\n currentUserId?: string;\n /** Other party user ids (role \"party\"); tool resolves names via getUser. Ignored if actors is provided. */\n otherPartyUserIds?: string[];\n /** Override actors with specific roles for role-based visibility tests. */\n actors?: MockOpportunityActor[];\n}): Opportunity {\n const id = overrides.id ?? `opp-${Date.now()}`;\n const networkId = overrides.networkId ?? \"idx-1\";\n const otherIds = overrides.otherPartyUserIds ?? [\"user-alice\"];\n const currentUserId = overrides.currentUserId ?? \"current-user\";\n const actors = overrides.actors ?? [\n { networkId, userId: currentUserId, role: \"party\" as const },\n ...otherIds.map((userId) => ({ networkId, userId, role: \"party\" as const })),\n ];\n return {\n id,\n detection: {\n source: \"opportunity_graph\" as const,\n timestamp: new Date().toISOString(),\n },\n actors,\n interpretation: { category: \"connection\", reasoning: \"Match\", confidence: 0.8 },\n context: { networkId },\n confidence: \"0.8\",\n status: overrides.status ?? \"latent\",\n createdAt: new Date(),\n updatedAt: new Date(),\n expiresAt: null,\n } as Opportunity;\n}\n\n/** Build a minimal IndexedIntentDetails for owner view. */\nexport function mockIndexedIntent(overrides: {\n id?: string;\n payload?: string;\n userId?: string;\n userName?: string;\n}): IndexedIntentDetails {\n return {\n id: overrides.id ?? `intent-${Date.now()}`,\n payload: overrides.payload ?? \"Looking for a co-founder\",\n summary: null,\n userId: overrides.userId ?? \"user-1\",\n userName: overrides.userName ?? \"Alice\",\n createdAt: new Date(),\n };\n}\n\n/** Build a minimal ActiveIntent. */\nexport function mockActiveIntent(overrides: { id?: string; payload?: string }): ActiveIntent {\n return {\n id: overrides.id ?? `intent-${Date.now()}`,\n payload: overrides.payload ?? \"Looking for a technical co-founder\",\n summary: null,\n createdAt: new Date(),\n };\n}\n\n/** Build a minimal profile fixture. */\nexport function mockProfile(overrides: { userId?: string; name?: string }): MockProfileFixture {\n const userId = overrides.userId ?? \"user-1\";\n return {\n id: `profile-${userId}`,\n userId,\n identity: {\n name: overrides.name ?? \"Test User\",\n bio: \"Test bio\",\n location: \"NYC\",\n },\n context: \"Test context\",\n embedding: null,\n };\n}\n\n/**\n * Create a ChatGraphCompositeDatabase mock from config.\n * Any method not overridden by config uses a safe noop/default.\n */\nexport function createChatGraphMockDb(\n config: ChatGraphMockConfig = {}\n): ChatGraphCompositeDatabase {\n const profile = config.profile ?? null;\n const activeIntents = config.activeIntents ?? (() => []);\n const intentsInIndexForMember = config.intentsInIndexForMember ?? (() => []);\n const indexIntentsForOwner = config.indexIntentsForOwner ?? (() => []);\n const opportunitiesForUser = config.opportunitiesForUser ?? (() => []);\n const networkMemberships = config.networkMemberships ?? (() => []);\n const getNetwork = config.getNetwork ?? (() => null);\n const isNetworkMember = config.isNetworkMember ?? (() => false);\n const isIndexOwner = config.isIndexOwner ?? (() => false);\n const getUser =\n config.getUser ??\n ((userId: string): UserRecord => ({ id: userId, name: \"Test User\", email: \"test@example.com\", socials: [] }));\n const ownedIndexes = config.ownedIndexes ?? (() => []);\n\n return {\n getProfile: async () => (profile ? { ...profile } : null),\n getProfileByUserId: async () => (profile ? { ...profile } : null),\n getActiveIntents: async (userId: string) =>\n Promise.resolve(activeIntents(userId)).then((f) => (Array.isArray(f) ? f : [])),\n getIntentsInIndexForMember: async (userId: string, networkId: string) =>\n Promise.resolve(intentsInIndexForMember(userId, networkId)).then((f) =>\n Array.isArray(f) ? f : []\n ),\n getUser: async (userId: string) => Promise.resolve(getUser(userId)),\n updateUser: async (userId: string, data: any) => ({\n id: userId,\n name: data?.name ?? 'Test User',\n email: 'test@example.com',\n socials: data?.socials ?? null,\n location: data?.location ?? null,\n }),\n saveProfile: noop,\n createIntent: async (data: CreateIntentData) => ({\n id: `intent-${Date.now()}`,\n payload: data.payload,\n summary: null,\n isIncognito: false,\n createdAt: new Date(),\n updatedAt: new Date(),\n userId: data.userId,\n }),\n updateIntent: noopNull,\n archiveIntent: async () => ({ success: true }),\n getUserIndexIds: async (userId: string) => {\n const memberships = await Promise.resolve(networkMemberships(userId));\n return Array.isArray(memberships) ? memberships.map((m) => m.networkId) : [];\n },\n getNetworkMemberships: async (userId: string) =>\n Promise.resolve(networkMemberships(userId)).then((f) => (Array.isArray(f) ? f : [])),\n getNetwork: async (networkId: string) => Promise.resolve(getNetwork(networkId)),\n getNetworkMembership: async (networkId: string, userId: string) => {\n const index = await Promise.resolve(getNetwork(networkId));\n if (!index) return null;\n const member = await Promise.resolve(isNetworkMember(networkId, userId));\n return member ? { networkId, networkTitle: index.title, indexPrompt: null, permissions: [] } : null;\n },\n getNetworkWithPermissions: async () => null,\n getIntentForIndexing: noopNull,\n getNetworkMemberContext: noopNull,\n getNegotiationTaskForOpportunity: noopNull,\n getOpportunitiesForUser: async (userId: string) =>\n Promise.resolve(opportunitiesForUser(userId)).then((f) => (Array.isArray(f) ? f : [])),\n createOpportunity: async () => mockOpportunity({ currentUserId: \"system\" }) as Opportunity,\n getOpportunity: noopNull,\n opportunityExistsBetweenActors: async () => false,\n findOpportunitiesByActors: async () => [],\n updateOpportunityStatus: noopNull,\n getHydeDocument: noopNull,\n getHydeDocumentsForSource: noopArray,\n saveHydeDocument: noop,\n getIntent: noopNull,\n isIntentAssignedToIndex: noopBool,\n assignIntentToNetwork: noop,\n unassignIntentFromIndex: noop,\n getNetworkIdsForIntent: noopArray,\n getOwnedIndexes: async (userId: string) =>\n Promise.resolve(ownedIndexes(userId)).then((f) => (Array.isArray(f) ? f : [])),\n isIndexOwner: async (networkId: string, userId: string) =>\n Promise.resolve(isIndexOwner(networkId, userId)),\n isNetworkMember: async (networkId: string, userId: string) =>\n Promise.resolve(isNetworkMember(networkId, userId)),\n getNetworkMembersForOwner: noopArray,\n getNetworkMembersForMember: noopArray,\n getMembersFromUserIndexes: async () => [],\n removeMemberFromIndex: async () => ({ success: true }),\n getNetworkIntentsForOwner: async (networkId: string, requestingUserId: string, opts?: { limit?: number; offset?: number }) =>\n Promise.resolve(indexIntentsForOwner(networkId, requestingUserId)).then((f) =>\n Array.isArray(f) ? f : []\n ),\n getNetworkIntentsForMember: async () => [],\n updateIndexSettings: async () => defaultOwnedIndex(),\n softDeleteNetwork: noop,\n deleteProfile: noop,\n createNetwork: async () => defaultOwnedIndex(),\n getNetworkMemberCount: async () => 0,\n addMemberToNetwork: noop,\n } as unknown as ChatGraphCompositeDatabase;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// MOCK CHAT SESSION READER & PROTOCOL DEPS\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/** Mock ChatSessionReader with stub implementations for graph tests. */\nexport const mockChatSessionReader: ChatSessionReader = {\n getSessionMessages: async () => [],\n listSessions: async () => [],\n getSession: async () => null,\n};\n\n/**\n * Create a mock ProtocolDeps with stub implementations for all fields.\n * Pass overrides to customise individual deps for specific tests.\n */\nexport function createMockProtocolDeps(overrides?: Partial<ProtocolDeps>): ProtocolDeps {\n // NOTE: database, embedder, scraper are intentionally omitted.\n // ChatGraphFactory spreads protocolDeps over {database, embedder, scraper, ...},\n // so including stubs here would overwrite the real mocks passed to the constructor.\n return {\n cache: { get: async () => null, set: async () => {}, delete: async () => false, exists: async () => false, mget: async () => [], deleteByPattern: async () => 0 },\n hydeCache: { get: async () => null, set: async () => {}, delete: async () => false, exists: async () => false },\n \n integration: { createSession: async () => ({ toolkits: async () => ({ items: [] }), authorize: async () => ({ redirectUrl: \"\" }) }), executeToolAction: async () => ({ successful: true }), listConnections: async () => [], getAuthUrl: async () => ({ redirectUrl: \"\" }), disconnect: async () => ({ success: true }) } as unknown as ProtocolDeps[\"integration\"],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n intentQueue: { addGenerateHydeJob: async () => ({}), addDeleteHydeJob: async () => ({}) } as any,\n contactService: { importContacts: async () => ({ imported: 0, skipped: 0, newContacts: 0, existingContacts: 0, details: [] }), listContacts: async () => [], addContact: async () => ({ userId: \"\", isNew: false, isGhost: false }), removeContact: async () => {} } as unknown as ProtocolDeps[\"contactService\"],\n chatSession: mockChatSessionReader,\n enricher: { enrichUserProfile: async () => null } as unknown as ProtocolDeps[\"enricher\"],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n negotiationDatabase: {} as any,\n integrationImporter: { importContacts: async () => ({ imported: 0, skipped: 0, newContacts: 0, existingContacts: 0 }) },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n createUserDatabase: (db: any, _userId: string) => {\n return new Proxy({}, {\n get: (_target, prop) => db[prop] ?? (async () => null),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }) as any;\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n createSystemDatabase: (db: any, _userId: string, _scope: string[]) => {\n return new Proxy({}, {\n get: (_target, prop) => db[prop] ?? (async () => null),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }) as any;\n },\n ...overrides,\n } as ProtocolDeps;\n}\n"]}
1
+ {"version":3,"file":"chat.graph.mocks.js","sourceRoot":"/","sources":["chat/tests/chat.graph.mocks.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Configurable mock database and fixture data for chat graph workflow tests.\n * Use createChatGraphMockDb(config) to get a full ChatGraphCompositeDatabase\n * with controllable profile, intents, network membership, and opportunities.\n */\n\nimport type { ChatGraphCompositeDatabase, CreateIntentData, ActiveIntent, IndexedIntentDetails, NetworkMembership, OwnedIndex, UserRecord, Opportunity, OpportunityStatus } from \"../../shared/interfaces/database.interface.js\";\nimport type { ChatSessionReader } from \"../../shared/interfaces/chat-session.interface.js\";\nimport type { ProtocolDeps } from \"../../shared/agent/tool.helpers.js\";\n\n// Minimal profile shape for getProfileByUserId (UserIdentity-shaped: identity + context)\nexport interface MockProfileFixture {\n id: string;\n userId: string;\n identity: { name: string; bio: string; location: string };\n context: string;\n embedding: number[] | null;\n}\n\nexport interface ChatGraphMockConfig {\n /** Profile for the session user (null = no profile). */\n profile?: MockProfileFixture | null;\n /** Active intents per userId (global scope). */\n activeIntents?: (userId: string) => ActiveIntent[] | Promise<ActiveIntent[]>;\n /** Intents in index for a member (userId, networkId) -> member's intents in that index. */\n intentsInIndexForMember?: (\n userId: string,\n networkId: string\n ) => ActiveIntent[] | Promise<ActiveIntent[]>;\n /** All intents in index (owner view). (networkId, requestingUserId) -> details. */\n indexIntentsForOwner?: (\n networkId: string,\n requestingUserId: string\n ) => IndexedIntentDetails[] | Promise<IndexedIntentDetails[]>;\n /** Opportunities for user. */\n opportunitiesForUser?: (userId: string) => Opportunity[] | Promise<Opportunity[]>;\n /** Network memberships for user. */\n networkMemberships?: (userId: string) => NetworkMembership[] | Promise<NetworkMembership[]>;\n /** Index by id (for scope validation). */\n getNetwork?: (networkId: string) => { id: string; title: string } | null | Promise<{ id: string; title: string } | null>;\n /** (networkId, userId) -> is member. */\n isNetworkMember?: (networkId: string, userId: string) => boolean | Promise<boolean>;\n /** (networkId, userId) -> is owner. */\n isIndexOwner?: (networkId: string, userId: string) => boolean | Promise<boolean>;\n /** User record by id. */\n getUser?: (userId: string) => UserRecord | null | Promise<UserRecord | null>;\n /** Owned indexes for user. */\n ownedIndexes?: (userId: string) => OwnedIndex[] | Promise<OwnedIndex[]>;\n}\n\nconst noop = async (): Promise<undefined> => undefined;\nconst noopArray = async <T>(): Promise<T[]> => [];\nconst noopNull = async (): Promise<null> => null;\nconst noopBool = async (): Promise<boolean> => false;\n\nconst defaultOwnedIndex = (): OwnedIndex => ({\n id: \"\",\n title: \"\",\n prompt: null,\n imageUrl: null,\n permissions: {\n joinPolicy: \"anyone\",\n allowGuestVibeCheck: false,\n invitationLink: null,\n },\n isPersonal: false,\n createdAt: new Date(),\n updatedAt: new Date(),\n memberCount: 0,\n intentCount: 0,\n user: { id: \"\", name: \"\", avatar: null },\n _count: { members: 0 },\n});\n\n/** Actor shape for opportunity mocks (role determines visibility). */\nexport type MockOpportunityActor = { networkId: string; userId: string; role: \"introducer\" | \"patient\" | \"agent\" | \"peer\" | \"party\"; intent?: string };\n\n/** Build a minimal Opportunity for list_opportunities / discover_opportunities tests. */\nexport function mockOpportunity(overrides: {\n id?: string;\n status?: OpportunityStatus;\n networkId?: string;\n /** Current user (must be one of the actors so they \"have\" this opportunity). */\n currentUserId?: string;\n /** Other party user ids (role \"party\"); tool resolves names via getUser. Ignored if actors is provided. */\n otherPartyUserIds?: string[];\n /** Override actors with specific roles for role-based visibility tests. */\n actors?: MockOpportunityActor[];\n}): Opportunity {\n const id = overrides.id ?? `opp-${Date.now()}`;\n const networkId = overrides.networkId ?? \"idx-1\";\n const otherIds = overrides.otherPartyUserIds ?? [\"user-alice\"];\n const currentUserId = overrides.currentUserId ?? \"current-user\";\n const actors = overrides.actors ?? [\n { networkId, userId: currentUserId, role: \"party\" as const },\n ...otherIds.map((userId) => ({ networkId, userId, role: \"party\" as const })),\n ];\n return {\n id,\n detection: {\n source: \"opportunity_graph\" as const,\n timestamp: new Date().toISOString(),\n },\n actors,\n interpretation: { category: \"connection\", reasoning: \"Match\", confidence: 0.8 },\n context: { networkId },\n confidence: \"0.8\",\n status: overrides.status ?? \"latent\",\n createdAt: new Date(),\n updatedAt: new Date(),\n expiresAt: null,\n } as Opportunity;\n}\n\n/** Build a minimal IndexedIntentDetails for owner view. */\nexport function mockIndexedIntent(overrides: {\n id?: string;\n payload?: string;\n userId?: string;\n userName?: string;\n}): IndexedIntentDetails {\n return {\n id: overrides.id ?? `intent-${Date.now()}`,\n payload: overrides.payload ?? \"Looking for a co-founder\",\n summary: null,\n userId: overrides.userId ?? \"user-1\",\n userName: overrides.userName ?? \"Alice\",\n createdAt: new Date(),\n };\n}\n\n/** Build a minimal ActiveIntent. */\nexport function mockActiveIntent(overrides: { id?: string; payload?: string }): ActiveIntent {\n return {\n id: overrides.id ?? `intent-${Date.now()}`,\n payload: overrides.payload ?? \"Looking for a technical co-founder\",\n summary: null,\n createdAt: new Date(),\n };\n}\n\n/** Build a minimal profile fixture. */\nexport function mockProfile(overrides: { userId?: string; name?: string }): MockProfileFixture {\n const userId = overrides.userId ?? \"user-1\";\n return {\n id: `profile-${userId}`,\n userId,\n identity: {\n name: overrides.name ?? \"Test User\",\n bio: \"Test bio\",\n location: \"NYC\",\n },\n context: \"Test context\",\n embedding: null,\n };\n}\n\n/**\n * Create a ChatGraphCompositeDatabase mock from config.\n * Any method not overridden by config uses a safe noop/default.\n */\nexport function createChatGraphMockDb(\n config: ChatGraphMockConfig = {}\n): ChatGraphCompositeDatabase {\n const profile = config.profile ?? null;\n const activeIntents = config.activeIntents ?? (() => []);\n const intentsInIndexForMember = config.intentsInIndexForMember ?? (() => []);\n const indexIntentsForOwner = config.indexIntentsForOwner ?? (() => []);\n const opportunitiesForUser = config.opportunitiesForUser ?? (() => []);\n const networkMemberships = config.networkMemberships ?? (() => []);\n const getNetwork = config.getNetwork ?? (() => null);\n const isNetworkMember = config.isNetworkMember ?? (() => false);\n const isIndexOwner = config.isIndexOwner ?? (() => false);\n const getUser =\n config.getUser ??\n ((userId: string): UserRecord => ({ id: userId, name: \"Test User\", email: \"test@example.com\", socials: [] }));\n const ownedIndexes = config.ownedIndexes ?? (() => []);\n\n return {\n getProfile: async () => (profile ? { ...profile } : null),\n getProfileByUserId: async () => (profile ? { ...profile } : null),\n getActiveIntents: async (userId: string) =>\n Promise.resolve(activeIntents(userId)).then((f) => (Array.isArray(f) ? f : [])),\n getIntentsInIndexForMember: async (userId: string, networkId: string) =>\n Promise.resolve(intentsInIndexForMember(userId, networkId)).then((f) =>\n Array.isArray(f) ? f : []\n ),\n getUser: async (userId: string) => Promise.resolve(getUser(userId)),\n updateUser: async (userId: string, data: any) => ({\n id: userId,\n name: data?.name ?? 'Test User',\n email: 'test@example.com',\n socials: data?.socials ?? null,\n location: data?.location ?? null,\n }),\n saveProfile: noop,\n createIntent: async (data: CreateIntentData) => ({\n id: `intent-${Date.now()}`,\n payload: data.payload,\n summary: null,\n isIncognito: false,\n createdAt: new Date(),\n updatedAt: new Date(),\n userId: data.userId,\n }),\n updateIntent: noopNull,\n archiveIntent: async () => ({ success: true }),\n getUserIndexIds: async (userId: string) => {\n const memberships = await Promise.resolve(networkMemberships(userId));\n return Array.isArray(memberships) ? memberships.map((m) => m.networkId) : [];\n },\n getNetworkMemberships: async (userId: string) =>\n Promise.resolve(networkMemberships(userId)).then((f) => (Array.isArray(f) ? f : [])),\n getNetwork: async (networkId: string) => Promise.resolve(getNetwork(networkId)),\n getNetworkMembership: async (networkId: string, userId: string) => {\n const index = await Promise.resolve(getNetwork(networkId));\n if (!index) return null;\n const member = await Promise.resolve(isNetworkMember(networkId, userId));\n return member ? { networkId, networkTitle: index.title, indexPrompt: null, permissions: [] } : null;\n },\n getNetworkWithPermissions: async () => null,\n getIntentForIndexing: noopNull,\n getNetworkMemberContext: noopNull,\n getNegotiationTaskForOpportunity: noopNull,\n getOpportunitiesForUser: async (userId: string) =>\n Promise.resolve(opportunitiesForUser(userId)).then((f) => (Array.isArray(f) ? f : [])),\n createOpportunity: async () => mockOpportunity({ currentUserId: \"system\" }) as Opportunity,\n getOpportunity: noopNull,\n opportunityExistsBetweenActors: async () => false,\n findOpportunitiesByActors: async () => [],\n updateOpportunityStatus: noopNull,\n getHydeDocument: noopNull,\n getHydeDocumentsForSource: noopArray,\n saveHydeDocument: noop,\n getIntent: noopNull,\n isIntentAssignedToIndex: noopBool,\n assignIntentToNetwork: noop,\n unassignIntentFromIndex: noop,\n getNetworkIdsForIntent: noopArray,\n getOwnedIndexes: async (userId: string) =>\n Promise.resolve(ownedIndexes(userId)).then((f) => (Array.isArray(f) ? f : [])),\n isIndexOwner: async (networkId: string, userId: string) =>\n Promise.resolve(isIndexOwner(networkId, userId)),\n isNetworkMember: async (networkId: string, userId: string) =>\n Promise.resolve(isNetworkMember(networkId, userId)),\n getNetworkMembersForOwner: noopArray,\n getNetworkMembersForMember: noopArray,\n getMembersFromUserIndexes: async () => [],\n removeMemberFromIndex: async () => ({ success: true }),\n getNetworkIntentsForOwner: async (networkId: string, requestingUserId: string, opts?: { limit?: number; offset?: number }) =>\n Promise.resolve(indexIntentsForOwner(networkId, requestingUserId)).then((f) =>\n Array.isArray(f) ? f : []\n ),\n getNetworkIntentsForMember: async () => [],\n updateIndexSettings: async () => defaultOwnedIndex(),\n softDeleteNetwork: noop,\n deleteProfile: noop,\n createNetwork: async () => defaultOwnedIndex(),\n getNetworkMemberCount: async () => 0,\n addMemberToNetwork: noop,\n } as unknown as ChatGraphCompositeDatabase;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════\n// MOCK CHAT SESSION READER & PROTOCOL DEPS\n// ═══════════════════════════════════════════════════════════════════════════════\n\n/** Mock ChatSessionReader with stub implementations for graph tests. */\nexport const mockChatSessionReader: ChatSessionReader = {\n getSessionMessages: async () => [],\n listSessions: async () => [],\n getSession: async () => null,\n};\n\n/**\n * Create a mock ProtocolDeps with stub implementations for all fields.\n * Pass overrides to customise individual deps for specific tests.\n */\nexport function createMockProtocolDeps(overrides?: Partial<ProtocolDeps>): ProtocolDeps {\n // NOTE: database, embedder, scraper are intentionally omitted.\n // ChatGraphFactory spreads protocolDeps over {database, embedder, scraper, ...},\n // so including stubs here would overwrite the real mocks passed to the constructor.\n return {\n cache: { get: async () => null, set: async () => {}, delete: async () => false, exists: async () => false, mget: async () => [], deleteByPattern: async () => 0 },\n hydeCache: { get: async () => null, set: async () => {}, delete: async () => false, exists: async () => false },\n\n integration: { createSession: async () => ({ toolkits: async () => ({ items: [] }), authorize: async () => ({ redirectUrl: \"\" }) }), executeToolAction: async () => ({ successful: true }), listConnections: async () => [], getAuthUrl: async () => ({ redirectUrl: \"\" }), disconnect: async () => ({ success: true }) } as unknown as ProtocolDeps[\"integration\"],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n intentQueue: { addGenerateHydeJob: async () => ({}), addDeleteHydeJob: async () => ({}) } as any,\n contactService: { importContacts: async () => ({ imported: 0, skipped: 0, newContacts: 0, existingContacts: 0, details: [] }), listContacts: async () => [], addContact: async () => ({ userId: \"\", isNew: false, isGhost: false }), removeContact: async () => {} } as unknown as ProtocolDeps[\"contactService\"],\n chatSession: mockChatSessionReader,\n enricher: { enrichUserProfile: async () => null } as unknown as ProtocolDeps[\"enricher\"],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n negotiationDatabase: {} as any,\n integrationImporter: { importContacts: async () => ({ imported: 0, skipped: 0, newContacts: 0, existingContacts: 0 }) },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n createUserDatabase: (db: any, _userId: string) => {\n return new Proxy({}, {\n get: (_target, prop) => db[prop] ?? (async () => null),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }) as any;\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n createSystemDatabase: (db: any, _userId: string, _scope: string[]) => {\n return new Proxy({}, {\n get: (_target, prop) => db[prop] ?? (async () => null),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }) as any;\n },\n ...overrides,\n } as ProtocolDeps;\n}\n"]}
@@ -16,8 +16,8 @@ export function createContactTools(defineTool, deps) {
16
16
  // side effect, so the call itself must be gated, not just the returned array.
17
17
  const import_contacts = contactsEnabled ? defineTool({
18
18
  name: 'import_contacts',
19
- description: "Bulk-imports contacts into the authenticated user's personal network (personal index). Contacts become members of the user's " +
20
- "personal index with 'contact' permission, making them available for opportunity discovery.\n\n" +
19
+ description: "Bulk-imports contacts into the authenticated user's personal network (personal network). Contacts become members of the user's " +
20
+ "personal network with 'contact' permission, making them available for opportunity discovery.\n\n" +
21
21
  "**What happens:** Each contact is matched by email. If the email belongs to an existing user, they're linked directly. " +
22
22
  "If not, a 'ghost user' is created — a placeholder account enriched with public profile data (from LinkedIn, GitHub, etc.) " +
23
23
  "that participates in opportunity matching even before the person joins the platform.\n\n" +
@@ -51,7 +51,7 @@ export function createContactTools(defineTool, deps) {
51
51
  const list_contacts = defineTool({
52
52
  name: 'list_contacts',
53
53
  description: "Lists all contacts in the authenticated user's personal network. Contacts are people the user has added " +
54
- "(via import_contacts, add_contact, or import_gmail_contacts) stored as members of their personal index.\n\n" +
54
+ "(via import_contacts, add_contact, or import_gmail_contacts) stored as members of their personal network.\n\n" +
55
55
  "**When to use:** To see who's in the user's network, find a contact's userId for other operations, " +
56
56
  "or check if a specific person is already a contact.\n\n" +
57
57
  "**Returns:** Array of contacts, each with: userId (use with read_user_contexts or discover_opportunities), " +
@@ -89,7 +89,7 @@ export function createContactTools(defineTool, deps) {
89
89
  "For bulk imports, use import_contacts instead.\n\n" +
90
90
  "**What happens:** Looks up the email. If an account exists, links that user as a contact. " +
91
91
  "If not, creates a ghost user (placeholder enriched with public profile data) and adds them. " +
92
- "The contact can then appear in opportunity discovery within the user's personal index.\n\n" +
92
+ "The contact can then appear in opportunity discovery within the user's personal network.\n\n" +
93
93
  "**When to use:** When the user wants to add a specific person (e.g. 'add john@example.com to my network').\n\n" +
94
94
  "**Returns:** Confirmation with the contact's userId and whether a new ghost user was created (isNewGhost). " +
95
95
  "Use the userId with discover_opportunities(targetUserId) to find connection opportunities.",
@@ -118,10 +118,10 @@ export function createContactTools(defineTool, deps) {
118
118
  const remove_contact = defineTool({
119
119
  name: 'remove_contact',
120
120
  description: "Removes a contact from the authenticated user's personal network. The contact relationship is deleted — " +
121
- "the person is no longer a member of the user's personal index and won't appear in personal-index-scoped discovery.\n\n" +
121
+ "the person is no longer a member of the user's personal network and won't appear in personal-network-scoped discovery.\n\n" +
122
122
  "**When to use:** When the user wants to remove someone from their network (e.g. 'remove John from my contacts').\n\n" +
123
123
  "**Note:** This only removes the contact relationship. If the contact is a real user (not a ghost), " +
124
- "they still exist on the platform and may appear in shared index discovery.\n\n" +
124
+ "they still exist on the platform and may appear in shared network discovery.\n\n" +
125
125
  "**Returns:** Confirmation that the contact was removed.",
126
126
  querySchema: z.object({
127
127
  contactUserId: z.string().describe('The userId of the contact to remove. Get this from list_contacts results.'),
@@ -1 +1 @@
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"]}
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 network). Contacts become members of the user's \" +\n \"personal network 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 network.\\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 network.\\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 network and won't appear in personal-network-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 network 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"]}
@@ -272,7 +272,7 @@ export function createEnrichmentTools(defineTool, deps) {
272
272
  "use these as the source of truth for whether the user still needs onboarding (do not rely on local file state).",
273
273
  querySchema: z.object({
274
274
  userId: z.string().optional().describe("Fetch a specific user's profile by their user ID. Get user IDs from read_network_memberships or list_contacts."),
275
- networkId: z.string().optional().describe("Index UUID — fetch profiles of all members in this index, or narrow a name search to this index. Get from read_networks."),
275
+ networkId: z.string().optional().describe("Network UUID — fetch profiles of all members in this network, or narrow a name search to this network. Get from read_networks."),
276
276
  query: z.string().optional().describe("Name to search for (case-insensitive substring match). Searches across all the user's indexes unless networkId is also provided. Use this when the user asks to 'find' or 'look up' someone."),
277
277
  }),
278
278
  handler: async ({ context, query }) => {
@@ -288,7 +288,7 @@ export function createEnrichmentTools(defineTool, deps) {
288
288
  if (nameQuery) {
289
289
  const pattern = nameQuery.toLowerCase();
290
290
  const MAX_RESULTS = 20;
291
- // When chat is index-scoped, restrict name search to that index
291
+ // When chat is network-scoped, restrict name search to that index
292
292
  const searchIndexId = effectiveIndexId || scopedNetworkId || undefined;
293
293
  let candidates;
294
294
  if (searchIndexId) {
@@ -348,16 +348,16 @@ export function createEnrichmentTools(defineTool, deps) {
348
348
  // When no userId / networkId / query is provided, fall through to Mode 1 (self lookup).
349
349
  // --- Mode 3: networkId provided → fetch all member profiles ---
350
350
  if (effectiveIndexId) {
351
- // Strict scope enforcement: when chat is index-scoped, only allow querying that index
351
+ // Strict scope enforcement: when chat is network-scoped, only allow querying that index
352
352
  if (scopedNetworkId && effectiveIndexId !== scopedNetworkId) {
353
353
  return error(`This chat is scoped to ${scopedIndexLabel}. You can only read profiles from this community.`);
354
354
  }
355
- // Verify the caller is a member of the index they're querying
355
+ // Verify the caller is a member of the network they're querying
356
356
  const callerIsMember = await systemDb.isNetworkMember(effectiveIndexId, context.userId);
357
357
  if (!callerIsMember) {
358
358
  return error("You can only read profiles from indexes you are a member of.");
359
359
  }
360
- // Use systemDb for cross-user access within shared indexes
360
+ // Use systemDb for cross-user access within shared networkes
361
361
  const members = await systemDb.getNetworkMembers(effectiveIndexId);
362
362
  const profiles = await Promise.all(members.map(async (member) => {
363
363
  const profile = await systemDb.getProfile(member.userId);
@@ -376,14 +376,14 @@ export function createEnrichmentTools(defineTool, deps) {
376
376
  }
377
377
  // --- Mode 2: userId provided (different user) → fetch single profile directly ---
378
378
  if (targetUserId && targetUserId !== context.userId) {
379
- // Strict scope enforcement: when chat is index-scoped, verify user is in that index
379
+ // Strict scope enforcement: when chat is network-scoped, verify user is in that index
380
380
  if (scopedNetworkId) {
381
381
  const isInScopedIndex = await systemDb.isNetworkMember(scopedNetworkId, targetUserId);
382
382
  if (!isInScopedIndex) {
383
383
  return error(`This chat is scoped to ${scopedIndexLabel}. You can only read profiles of members in this community.`);
384
384
  }
385
385
  }
386
- // Use systemDb for cross-user profile access (requires shared index)
386
+ // Use systemDb for cross-user profile access (requires shared network)
387
387
  const profile = await systemDb.getProfile(targetUserId);
388
388
  if (profile) {
389
389
  // Thin identity + the user's global user_context text (profile-replacing