@indexnetwork/protocol 4.3.2 → 4.3.4-rc.309.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 (119) hide show
  1. package/dist/chat/chat.agent.d.ts.map +1 -1
  2. package/dist/chat/chat.agent.js +11 -1
  3. package/dist/chat/chat.agent.js.map +1 -1
  4. package/dist/chat/chat.graph.d.ts +16 -0
  5. package/dist/chat/chat.graph.d.ts.map +1 -1
  6. package/dist/chat/chat.graph.js +5 -2
  7. package/dist/chat/chat.graph.js.map +1 -1
  8. package/dist/chat/chat.prompt.d.ts.map +1 -1
  9. package/dist/chat/chat.prompt.js +20 -13
  10. package/dist/chat/chat.prompt.js.map +1 -1
  11. package/dist/chat/chat.state.d.ts +6 -3
  12. package/dist/chat/chat.state.d.ts.map +1 -1
  13. package/dist/chat/chat.state.js +12 -3
  14. package/dist/chat/chat.state.js.map +1 -1
  15. package/dist/chat/chat.streamer.d.ts +5 -0
  16. package/dist/chat/chat.streamer.d.ts.map +1 -1
  17. package/dist/chat/chat.streamer.js +13 -4
  18. package/dist/chat/chat.streamer.js.map +1 -1
  19. package/dist/enrichment/enrichment.tools.d.ts.map +1 -1
  20. package/dist/enrichment/enrichment.tools.js +16 -19
  21. package/dist/enrichment/enrichment.tools.js.map +1 -1
  22. package/dist/index.d.ts +5 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +2 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/intent/intent.graph.d.ts +10 -0
  27. package/dist/intent/intent.graph.d.ts.map +1 -1
  28. package/dist/intent/intent.graph.js +6 -2
  29. package/dist/intent/intent.graph.js.map +1 -1
  30. package/dist/intent/intent.state.d.ts +5 -1
  31. package/dist/intent/intent.state.d.ts.map +1 -1
  32. package/dist/intent/intent.state.js +11 -1
  33. package/dist/intent/intent.state.js.map +1 -1
  34. package/dist/intent/intent.tools.d.ts.map +1 -1
  35. package/dist/intent/intent.tools.js +63 -39
  36. package/dist/intent/intent.tools.js.map +1 -1
  37. package/dist/mcp/mcp.server.d.ts +45 -18
  38. package/dist/mcp/mcp.server.d.ts.map +1 -1
  39. package/dist/mcp/mcp.server.js +86 -45
  40. package/dist/mcp/mcp.server.js.map +1 -1
  41. package/dist/negotiation/negotiation.tools.d.ts.map +1 -1
  42. package/dist/negotiation/negotiation.tools.js +11 -7
  43. package/dist/negotiation/negotiation.tools.js.map +1 -1
  44. package/dist/network/network.graph.js +2 -2
  45. package/dist/network/network.graph.js.map +1 -1
  46. package/dist/network/network.tools.d.ts.map +1 -1
  47. package/dist/network/network.tools.js +50 -38
  48. package/dist/network/network.tools.js.map +1 -1
  49. package/dist/opportunity/opportunity.discover.d.ts +5 -0
  50. package/dist/opportunity/opportunity.discover.d.ts.map +1 -1
  51. package/dist/opportunity/opportunity.discover.js +3 -0
  52. package/dist/opportunity/opportunity.discover.js.map +1 -1
  53. package/dist/opportunity/opportunity.graph.d.ts +6 -6
  54. package/dist/opportunity/opportunity.graph.js +1 -1
  55. package/dist/opportunity/opportunity.graph.js.map +1 -1
  56. package/dist/opportunity/opportunity.pending-questions.d.ts +3 -0
  57. package/dist/opportunity/opportunity.pending-questions.d.ts.map +1 -1
  58. package/dist/opportunity/opportunity.pending-questions.js +7 -2
  59. package/dist/opportunity/opportunity.pending-questions.js.map +1 -1
  60. package/dist/opportunity/opportunity.state.d.ts +1 -1
  61. package/dist/opportunity/opportunity.tools.d.ts.map +1 -1
  62. package/dist/opportunity/opportunity.tools.js +46 -36
  63. package/dist/opportunity/opportunity.tools.js.map +1 -1
  64. package/dist/premise/premise.graph.d.ts +13 -1
  65. package/dist/premise/premise.graph.d.ts.map +1 -1
  66. package/dist/premise/premise.graph.js +11 -6
  67. package/dist/premise/premise.graph.js.map +1 -1
  68. package/dist/premise/premise.state.d.ts +5 -0
  69. package/dist/premise/premise.state.d.ts.map +1 -1
  70. package/dist/premise/premise.state.js +11 -0
  71. package/dist/premise/premise.state.js.map +1 -1
  72. package/dist/premise/premise.tools.d.ts.map +1 -1
  73. package/dist/premise/premise.tools.js +5 -0
  74. package/dist/premise/premise.tools.js.map +1 -1
  75. package/dist/questioner/questioner.tools.d.ts +1 -1
  76. package/dist/questioner/questioner.tools.d.ts.map +1 -1
  77. package/dist/questioner/questioner.tools.js +24 -13
  78. package/dist/questioner/questioner.tools.js.map +1 -1
  79. package/dist/questioner/questioner.types.d.ts +5 -0
  80. package/dist/questioner/questioner.types.d.ts.map +1 -1
  81. package/dist/questioner/questioner.types.js.map +1 -1
  82. package/dist/shared/agent/tool.factory.d.ts.map +1 -1
  83. package/dist/shared/agent/tool.factory.js +25 -16
  84. package/dist/shared/agent/tool.factory.js.map +1 -1
  85. package/dist/shared/agent/tool.helpers.d.ts +17 -18
  86. package/dist/shared/agent/tool.helpers.d.ts.map +1 -1
  87. package/dist/shared/agent/tool.helpers.js +10 -11
  88. package/dist/shared/agent/tool.helpers.js.map +1 -1
  89. package/dist/shared/agent/tool.registry.js +1 -1
  90. package/dist/shared/agent/tool.registry.js.map +1 -1
  91. package/dist/shared/agent/tool.scope.d.ts +39 -0
  92. package/dist/shared/agent/tool.scope.d.ts.map +1 -0
  93. package/dist/shared/agent/tool.scope.js +41 -0
  94. package/dist/shared/agent/tool.scope.js.map +1 -0
  95. package/dist/shared/assignment/network-assignment.policy.d.ts +8 -5
  96. package/dist/shared/assignment/network-assignment.policy.d.ts.map +1 -1
  97. package/dist/shared/assignment/network-assignment.policy.js +11 -6
  98. package/dist/shared/assignment/network-assignment.policy.js.map +1 -1
  99. package/dist/shared/hyde/hyde.graph.d.ts +6 -6
  100. package/dist/shared/hyde/hyde.state.d.ts +2 -2
  101. package/dist/shared/interfaces/auth.interface.d.ts +3 -3
  102. package/dist/shared/interfaces/auth.interface.js.map +1 -1
  103. package/dist/shared/interfaces/database.interface.d.ts +15 -3
  104. package/dist/shared/interfaces/database.interface.d.ts.map +1 -1
  105. package/dist/shared/interfaces/database.interface.js.map +1 -1
  106. package/dist/shared/interfaces/discovery-run.interface.d.ts +1 -1
  107. package/dist/shared/interfaces/discovery-run.interface.d.ts.map +1 -1
  108. package/dist/shared/interfaces/discovery-run.interface.js.map +1 -1
  109. package/dist/shared/interfaces/enrichment-run.interface.d.ts +1 -1
  110. package/dist/shared/interfaces/enrichment-run.interface.d.ts.map +1 -1
  111. package/dist/shared/interfaces/enrichment-run.interface.js.map +1 -1
  112. package/dist/shared/interfaces/queue.interface.d.ts +8 -2
  113. package/dist/shared/interfaces/queue.interface.d.ts.map +1 -1
  114. package/dist/shared/interfaces/queue.interface.js.map +1 -1
  115. package/dist/shared/schemas/network-assignment.schema.d.ts +2 -2
  116. package/dist/shared/schemas/pending-question.schema.d.ts +5 -0
  117. package/dist/shared/schemas/pending-question.schema.d.ts.map +1 -1
  118. package/dist/shared/schemas/pending-question.schema.js.map +1 -1
  119. package/package.json +1 -1
@@ -5,10 +5,13 @@ export interface MergePendingQuestionsInput {
5
5
  findPendingQuestions?: (userId: string, filters?: {
6
6
  sourceType?: string;
7
7
  sourceId?: string;
8
+ networkId?: string;
8
9
  }) => Promise<PendingQuestionSummary[]>;
9
10
  userId: string;
10
11
  sourceType?: string;
11
12
  sourceId?: string;
13
+ /** Restrict to questions whose actor carries this network id. */
14
+ networkId?: string;
12
15
  /** IDs already shown in this chat session — skip them. */
13
16
  surfacedQuestionIds: Set<string>;
14
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"opportunity.pending-questions.d.ts","sourceRoot":"/","sources":["opportunity/opportunity.pending-questions.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8CAA8C,CAAC;AAI3F,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,MAAM,WAAW,0BAA0B;IACzC,oBAAoB,CAAC,EAAE,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KACjD,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,2BAA2B;IAC1C,0EAA0E;IAC1E,SAAS,EAAE,sBAAsB,EAAE,CAAC;IACpC,0FAA0F;IAC1F,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,2BAA2B,CAAC,CAyBtC"}
1
+ {"version":3,"file":"opportunity.pending-questions.d.ts","sourceRoot":"/","sources":["opportunity/opportunity.pending-questions.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8CAA8C,CAAC;AAI3F,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,MAAM,WAAW,0BAA0B;IACzC,oBAAoB,CAAC,EAAE,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KACrE,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,2BAA2B;IAC1C,0EAA0E;IAC1E,SAAS,EAAE,sBAAsB,EAAE,CAAC;IACpC,0FAA0F;IAC1F,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,2BAA2B,CAAC,CA8BtC"}
@@ -14,8 +14,13 @@ export async function mergePendingQuestions(input) {
14
14
  if (!input.findPendingQuestions) {
15
15
  return { questions: [], surfacedIds: [] };
16
16
  }
17
- const filters = input.sourceType
18
- ? { sourceType: input.sourceType, ...(input.sourceId ? { sourceId: input.sourceId } : {}) }
17
+ const hasFilters = Boolean(input.sourceType || input.networkId);
18
+ const filters = hasFilters
19
+ ? {
20
+ ...(input.sourceType ? { sourceType: input.sourceType } : {}),
21
+ ...(input.sourceId ? { sourceId: input.sourceId } : {}),
22
+ ...(input.networkId ? { networkId: input.networkId } : {}),
23
+ }
19
24
  : undefined;
20
25
  let pending;
21
26
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"opportunity.pending-questions.js","sourceRoot":"/","sources":["opportunity/opportunity.pending-questions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAG5E,MAAM,MAAM,GAAG,cAAc,CAAC,kBAAkB,CAAC,CAAC;AAElD,kEAAkE;AAClE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAqBvC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAiC;IAEjC,IAAI,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAChC,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC5C,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU;QAC9B,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;QAC3F,CAAC,CAAC,SAAS,CAAC;IAEd,IAAI,OAAiC,CAAC;IACtC,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,oDAAoD,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAClF,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC5C,CAAC;IAED,2DAA2D;IAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAErD,OAAO;QACL,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Helper for merging pending questions from the DB into tool results.\n * Extracted so it can be unit-tested independently of the tool handler.\n */\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport type { PendingQuestionSummary } from \"../shared/schemas/pending-question.schema.js\";\n\nconst logger = protocolLogger(\"PendingQuestions\");\n\n/** Maximum pending questions attached to a single tool result. */\nexport const MAX_PENDING_QUESTIONS = 3;\n\nexport interface MergePendingQuestionsInput {\n findPendingQuestions?: (\n userId: string,\n filters?: { sourceType?: string; sourceId?: string },\n ) => Promise<PendingQuestionSummary[]>;\n userId: string;\n sourceType?: string;\n sourceId?: string;\n /** IDs already shown in this chat session — skip them. */\n surfacedQuestionIds: Set<string>;\n}\n\nexport interface MergePendingQuestionsResult {\n /** Questions to attach to the tool result (under the `questions` key). */\n questions: PendingQuestionSummary[];\n /** IDs of the questions that were included (caller should add to surfacedQuestionIds). */\n surfacedIds: string[];\n}\n\n/**\n * Query pending questions and filter out already-surfaced ones.\n * Returns at most MAX_PENDING_QUESTIONS entries.\n */\nexport async function mergePendingQuestions(\n input: MergePendingQuestionsInput,\n): Promise<MergePendingQuestionsResult> {\n if (!input.findPendingQuestions) {\n return { questions: [], surfacedIds: [] };\n }\n\n const filters = input.sourceType\n ? { sourceType: input.sourceType, ...(input.sourceId ? { sourceId: input.sourceId } : {}) }\n : undefined;\n\n let pending: PendingQuestionSummary[];\n try {\n pending = await input.findPendingQuestions(input.userId, filters);\n } catch (err) {\n logger.warn('Failed to fetch pending questions, returning empty', { error: err });\n return { questions: [], surfacedIds: [] };\n }\n\n // Deduplicate against already-surfaced IDs in this session\n const fresh = pending.filter((q) => !input.surfacedQuestionIds.has(q.id));\n const capped = fresh.slice(0, MAX_PENDING_QUESTIONS);\n\n return {\n questions: capped,\n surfacedIds: capped.map((q) => q.id),\n };\n}\n"]}
1
+ {"version":3,"file":"opportunity.pending-questions.js","sourceRoot":"/","sources":["opportunity/opportunity.pending-questions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAG5E,MAAM,MAAM,GAAG,cAAc,CAAC,kBAAkB,CAAC,CAAC;AAElD,kEAAkE;AAClE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAuBvC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAiC;IAEjC,IAAI,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAChC,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC5C,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,UAAU;QACxB,CAAC,CAAC;YACE,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3D;QACH,CAAC,CAAC,SAAS,CAAC;IAEd,IAAI,OAAiC,CAAC;IACtC,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,oDAAoD,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAClF,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC5C,CAAC;IAED,2DAA2D;IAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAErD,OAAO;QACL,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Helper for merging pending questions from the DB into tool results.\n * Extracted so it can be unit-tested independently of the tool handler.\n */\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport type { PendingQuestionSummary } from \"../shared/schemas/pending-question.schema.js\";\n\nconst logger = protocolLogger(\"PendingQuestions\");\n\n/** Maximum pending questions attached to a single tool result. */\nexport const MAX_PENDING_QUESTIONS = 3;\n\nexport interface MergePendingQuestionsInput {\n findPendingQuestions?: (\n userId: string,\n filters?: { sourceType?: string; sourceId?: string; networkId?: string },\n ) => Promise<PendingQuestionSummary[]>;\n userId: string;\n sourceType?: string;\n sourceId?: string;\n /** Restrict to questions whose actor carries this network id. */\n networkId?: string;\n /** IDs already shown in this chat session — skip them. */\n surfacedQuestionIds: Set<string>;\n}\n\nexport interface MergePendingQuestionsResult {\n /** Questions to attach to the tool result (under the `questions` key). */\n questions: PendingQuestionSummary[];\n /** IDs of the questions that were included (caller should add to surfacedQuestionIds). */\n surfacedIds: string[];\n}\n\n/**\n * Query pending questions and filter out already-surfaced ones.\n * Returns at most MAX_PENDING_QUESTIONS entries.\n */\nexport async function mergePendingQuestions(\n input: MergePendingQuestionsInput,\n): Promise<MergePendingQuestionsResult> {\n if (!input.findPendingQuestions) {\n return { questions: [], surfacedIds: [] };\n }\n\n const hasFilters = Boolean(input.sourceType || input.networkId);\n const filters = hasFilters\n ? {\n ...(input.sourceType ? { sourceType: input.sourceType } : {}),\n ...(input.sourceId ? { sourceId: input.sourceId } : {}),\n ...(input.networkId ? { networkId: input.networkId } : {}),\n }\n : undefined;\n\n let pending: PendingQuestionSummary[];\n try {\n pending = await input.findPendingQuestions(input.userId, filters);\n } catch (err) {\n logger.warn('Failed to fetch pending questions, returning empty', { error: err });\n return { questions: [], surfacedIds: [] };\n }\n\n // Deduplicate against already-surfaced IDs in this session\n const fresh = pending.filter((q) => !input.surfacedQuestionIds.has(q.id));\n const capped = fresh.slice(0, MAX_PENDING_QUESTIONS);\n\n return {\n questions: capped,\n surfacedIds: capped.map((q) => q.id),\n };\n}\n"]}
@@ -259,7 +259,7 @@ export declare const OpportunityGraphState: import("@langchain/langgraph").Annot
259
259
  /** Per-index relevancy scores for dedup tie-breaking. Background path: from intent_indexes. Chat path: transient from IntentIndexer. */
260
260
  indexRelevancyScores: import("@langchain/langgraph").BaseChannel<Record<string, number>, Record<string, number> | import("@langchain/langgraph").OverwriteValue<Record<string, number>>, unknown>;
261
261
  /** Whether discovery used intent (path A) or user context (path B/C). Used by persist for triggeredBy. In-memory routing state only; never persisted. */
262
- discoverySource: import("@langchain/langgraph").BaseChannel<"intent" | "context", "intent" | "context" | import("@langchain/langgraph").OverwriteValue<"intent" | "context">, unknown>;
262
+ discoverySource: import("@langchain/langgraph").BaseChannel<"context" | "intent", "context" | "intent" | import("@langchain/langgraph").OverwriteValue<"context" | "intent">, unknown>;
263
263
  /** Resolved intent ID used for this discovery run (when discoverySource is 'intent'). Set by intent-resolution. */
264
264
  resolvedTriggerIntentId: import("@langchain/langgraph").BaseChannel<Id<"intents"> | undefined, Id<"intents"> | import("@langchain/langgraph").OverwriteValue<Id<"intents"> | undefined> | undefined, unknown>;
265
265
  /** Asker's profile (from prep). Used for profile-as-source discovery and evaluation. */
@@ -1 +1 @@
1
- {"version":3,"file":"opportunity.tools.d.ts","sourceRoot":"/","sources":["opportunity/opportunity.tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"opportunity.tools.d.ts","sourceRoot":"/","sources":["opportunity/opportunity.tools.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { requestContext } from "../shared/observability/request-context.js";
3
3
  import { success, error, UUID_REGEX } from "../shared/agent/tool.helpers.js";
4
+ import { deriveDiscoveryNetworkIds, focusedNetworkId, focusedNetworkLabel } from "../shared/agent/tool.scope.js";
4
5
  import { MINIMAL_MAIN_TEXT_MAX_CHARS, getPrimaryActionLabel, SECONDARY_ACTION_LABEL } from "./opportunity.labels.js";
5
6
  import { viewerCentricCardSummary, narratorRemarkFromReasoning, stripUuids } from "./opportunity.presentation.js";
6
7
  import { runDiscoverFromQuery, continueDiscovery } from "./opportunity.discover.js";
@@ -382,16 +383,16 @@ function discoveryRunSignature(input, scopeKey) {
382
383
  }
383
384
  /**
384
385
  * Stable key for the resolved discovery scope of a request. Two requests
385
- * coalesce only when they resolve to the same reach the focus index
386
- * (`networkId`) and the full reachable `indexScope` set. When `query.networkId`
387
- * is omitted, scope comes from context (network-scoped agent vs unscoped
388
- * session), so folding it into the signature prevents a scoped caller from
389
- * coalescing onto an unscoped run and receiving out-of-scope opportunities.
386
+ * coalesce only when they resolve to the same focused discovery boundary. For
387
+ * scoped contexts, that boundary is the scope envelope (`scopeType`/`scopeId`),
388
+ * not the personal-inclusive allowed network reach used for self-owned writes.
389
+ * Unscoped requests intentionally share a single empty-scope key; concrete
390
+ * allowed reach is derived from memberships at execution time.
390
391
  */
391
392
  function discoveryScopeKey(ctx) {
392
393
  return JSON.stringify({
393
- networkId: (ctx.networkId ?? "").trim(),
394
- indexScope: [...(ctx.indexScope ?? [])].map((s) => s.trim()).sort(),
394
+ scopeType: (ctx.scopeType ?? "").trim(),
395
+ scopeId: (ctx.scopeId ?? "").trim(),
395
396
  });
396
397
  }
397
398
  function confirmDeliveryError(code, retryable, message) {
@@ -458,7 +459,7 @@ export function createOpportunityTools(defineTool, deps) {
458
459
  networkId: z
459
460
  .string()
460
461
  .optional()
461
- .describe("Index UUID to scope discovery to a specific community. Get from read_networks. In an index-scoped chat, omitting this runs discovery across the full reachable scope (the bound community plus the user's personal index); pass an explicit networkId to force single-index discovery. Pass the personal index ID (from read_networks, isPersonal=true) to scope to the user's contacts only."),
462
+ .describe("Index UUID to scope discovery to a specific community. Get from read_networks. In an index-scoped chat, omitting this runs discovery only in the scoped community; pass the personal index ID (from read_networks, isPersonal=true) only when the user explicitly asks to discover among contacts."),
462
463
  intentId: z
463
464
  .string()
464
465
  .optional()
@@ -514,18 +515,18 @@ export function createOpportunityTools(defineTool, deps) {
514
515
  "'complementary skills for a startup'). Helps the evaluator produce better match reasoning."),
515
516
  }),
516
517
  handler: async ({ context, query }) => {
518
+ const scopedNetworkId = focusedNetworkId(context);
519
+ const scopedIndexLabel = focusedNetworkLabel(context);
517
520
  // Strict scope enforcement: when chat is index-scoped, only allow that index
518
- if (context.networkId &&
521
+ if (scopedNetworkId &&
519
522
  query.networkId?.trim() &&
520
- query.networkId.trim() !== context.networkId) {
521
- return error(`This chat is scoped to ${context.indexName ?? "this index"}. You can only create opportunities in this community.`);
523
+ query.networkId.trim() !== scopedNetworkId) {
524
+ return error(`This chat is scoped to ${scopedIndexLabel}. You can only create opportunities in this community.`);
522
525
  }
523
526
  // Distinguish an explicit `query.networkId` override (caller wants discovery
524
- // scoped to one specific index) from an implicit scoped-chat context
525
- // (caller is in a scoped chat with no explicit override — discovery should
526
- // span the chat's reach, i.e. context.indexScope = [bound, personal]).
527
- // Conflating them via `context.networkId || query.networkId` made the
528
- // implicit branch unreachable.
527
+ // scoped to one specific index) from an implicit scoped-chat context.
528
+ // Scoped-chat discovery stays focused to the scoped community only; the
529
+ // personal-inclusive allowed reach is reserved for self-owned writes.
529
530
  const explicitIndexId = query.networkId?.trim() || undefined;
530
531
  const effectiveIndexId = explicitIndexId;
531
532
  if (effectiveIndexId && !UUID_REGEX.test(effectiveIndexId)) {
@@ -565,9 +566,8 @@ export function createOpportunityTools(defineTool, deps) {
565
566
  userId: context.userId,
566
567
  userName: context.userName,
567
568
  userEmail: context.userEmail,
568
- ...(context.networkId ? { networkId: context.networkId } : {}),
569
+ ...(scopedNetworkId ? { scopeType: 'network', scopeId: scopedNetworkId } : {}),
569
570
  ...(context.indexName ? { indexName: context.indexName } : {}),
570
- indexScope: context.indexScope,
571
571
  ...(context.sessionId ? { sessionId: context.sessionId } : {}),
572
572
  ...(context.agentId ? { agentId: context.agentId } : {}),
573
573
  ...(context.clientSurface ? { clientSurface: context.clientSurface } : {}),
@@ -614,7 +614,7 @@ export function createOpportunityTools(defineTool, deps) {
614
614
  cache,
615
615
  userId: context.userId,
616
616
  discoveryId: query.continueFrom,
617
- expectedIndexId: context.networkId,
617
+ expectedIndexId: scopedNetworkId,
618
618
  limit: 20,
619
619
  presenter: createOpportunityPresenter(),
620
620
  useHomeCardFormat: true,
@@ -729,7 +729,7 @@ export function createOpportunityTools(defineTool, deps) {
729
729
  networkId: primaryNetworkId,
730
730
  introductionEntities: evaluatorEntities,
731
731
  introductionHint: query.hint,
732
- requiredNetworkId: context.networkId ?? undefined,
732
+ requiredNetworkId: scopedNetworkId,
733
733
  options: {
734
734
  initialStatus: "draft",
735
735
  ...(context.sessionId ? { conversationId: context.sessionId } : {}),
@@ -863,12 +863,19 @@ export function createOpportunityTools(defineTool, deps) {
863
863
  }
864
864
  indexScope = [effectiveIndexId];
865
865
  }
866
- else if (context.networkId) {
867
- // Scoped chat: use the agent's full reach so personal-index
868
- // signals participate in opportunity discovery. See IND-306.
869
- indexScope = context.indexScope.length > 0
870
- ? [...context.indexScope]
871
- : [context.networkId];
866
+ else if (context.scopeType === 'network' && context.scopeId) {
867
+ // Scoped chat: discovery is focused-network only. Self-owned writes may
868
+ // include personal indexes, but opportunity visibility must not.
869
+ const scopedDiscoveryIds = deriveDiscoveryNetworkIds({
870
+ memberships: context.userNetworks,
871
+ scopeType: context.scopeType,
872
+ scopeId: context.scopeId,
873
+ });
874
+ indexScope = scopedDiscoveryIds;
875
+ }
876
+ else if (scopedNetworkId) {
877
+ // Scoped context: preserve focused-only discovery using the scope envelope.
878
+ indexScope = [scopedNetworkId];
872
879
  }
873
880
  else {
874
881
  // No scope - use all indexes (only in unscoped chat)
@@ -933,6 +940,7 @@ export function createOpportunityTools(defineTool, deps) {
933
940
  ...(deps.chatSummary && { chatSummary: deps.chatSummary }),
934
941
  ...(deps.questionGenerator && { questionGenerator: deps.questionGenerator }),
935
942
  ...(deps.questionerEnqueue && { questionerEnqueue: deps.questionerEnqueue }),
943
+ ...(context.scopeType && context.scopeId ? { scopeType: context.scopeType, scopeId: context.scopeId } : {}),
936
944
  ...(deps.negotiationSummary && { negotiationSummary: deps.negotiationSummary }),
937
945
  // Decision questions add an LLM call after the negotiation phase.
938
946
  // Capped at DISCOVERY_QUESTIONS_TIMEOUT_MS (12 s default,
@@ -956,6 +964,7 @@ export function createOpportunityTools(defineTool, deps) {
956
964
  findPendingQuestions: deps.findPendingQuestions,
957
965
  userId: context.userId,
958
966
  sourceType: 'discovery',
967
+ ...(context.scopeType === 'network' && context.scopeId ? { networkId: context.scopeId } : {}),
959
968
  surfacedQuestionIds: new Set(), // Dedup handled at chat.agent level
960
969
  });
961
970
  const pendingQuestions = pendingQuestionResult.questions;
@@ -1298,15 +1307,15 @@ export function createOpportunityTools(defineTool, deps) {
1298
1307
  .describe("Internal scheduled-digest mode only. When true, includes hidden delivery markers so the digest send pass can confirm only edited-in opportunities."),
1299
1308
  }),
1300
1309
  handler: async ({ context, query }) => {
1310
+ const scopedNetworkId = focusedNetworkId(context);
1311
+ const scopedIndexLabel = focusedNetworkLabel(context);
1301
1312
  // Strict scope enforcement: when chat is index-scoped, only allow that index
1302
- if (context.networkId &&
1313
+ if (scopedNetworkId &&
1303
1314
  query.networkId?.trim() &&
1304
- query.networkId.trim() !== context.networkId) {
1305
- return error("This chat is scoped to " +
1306
- (context.indexName ?? "this index") +
1307
- ". You can only list opportunities from this community.");
1315
+ query.networkId.trim() !== scopedNetworkId) {
1316
+ return error(`This chat is scoped to ${scopedIndexLabel}. You can only list opportunities from this community.`);
1308
1317
  }
1309
- const effectiveIndexId = (context.networkId || query.networkId?.trim()) ?? undefined;
1318
+ const effectiveIndexId = (scopedNetworkId || query.networkId?.trim()) ?? undefined;
1310
1319
  if (effectiveIndexId && !UUID_REGEX.test(effectiveIndexId)) {
1311
1320
  return error("Invalid network ID format.");
1312
1321
  }
@@ -1805,10 +1814,11 @@ export function createOpportunityTools(defineTool, deps) {
1805
1814
  // Strict scope enforcement: when chat is index-scoped, the caller's own
1806
1815
  // actor entry on this opportunity must be anchored on the bound network.
1807
1816
  // Mirrors the per-actor filter in getOpportunitiesForUser — relying on
1808
- // `context.networkId` or any-actor matches would let a counterpart's
1809
- // network presence shadow a viewer whose own actor is elsewhere.
1810
- if (context.networkId) {
1811
- const callerOnBoundNetwork = opportunity.actors?.some((a) => a.userId === context.userId && a.networkId === context.networkId);
1817
+ // a focus-scope id or any-actor matches would let a counterpart's network
1818
+ // presence shadow a viewer whose own actor is elsewhere.
1819
+ const scopedNetworkId = focusedNetworkId(context);
1820
+ if (scopedNetworkId) {
1821
+ const callerOnBoundNetwork = opportunity.actors?.some((a) => a.userId === context.userId && a.networkId === scopedNetworkId);
1812
1822
  if (!callerOnBoundNetwork) {
1813
1823
  return error("Opportunity not found.");
1814
1824
  }