@indexnetwork/protocol 0.33.0-rc.121.1 → 1.1.0-rc.123.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 (66) hide show
  1. package/dist/chat/chat-streaming.types.d.ts +62 -3
  2. package/dist/chat/chat-streaming.types.d.ts.map +1 -1
  3. package/dist/chat/chat-streaming.types.js +17 -1
  4. package/dist/chat/chat-streaming.types.js.map +1 -1
  5. package/dist/chat/chat.agent.d.ts +35 -1
  6. package/dist/chat/chat.agent.d.ts.map +1 -1
  7. package/dist/chat/chat.agent.js +54 -1
  8. package/dist/chat/chat.agent.js.map +1 -1
  9. package/dist/chat/chat.graph.d.ts +2 -0
  10. package/dist/chat/chat.graph.d.ts.map +1 -1
  11. package/dist/chat/chat.prompt.modules.d.ts.map +1 -1
  12. package/dist/chat/chat.prompt.modules.js +2 -0
  13. package/dist/chat/chat.prompt.modules.js.map +1 -1
  14. package/dist/chat/chat.streamer.d.ts.map +1 -1
  15. package/dist/chat/chat.streamer.js +17 -2
  16. package/dist/chat/chat.streamer.js.map +1 -1
  17. package/dist/chat/tests/chat.graph.mocks.d.ts.map +1 -1
  18. package/dist/chat/tests/chat.graph.mocks.js +1 -2
  19. package/dist/chat/tests/chat.graph.mocks.js.map +1 -1
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/negotiation/negotiation.graph.d.ts +9 -1
  24. package/dist/negotiation/negotiation.graph.d.ts.map +1 -1
  25. package/dist/negotiation/negotiation.graph.js +29 -2
  26. package/dist/negotiation/negotiation.graph.js.map +1 -1
  27. package/dist/opportunity/discovery-question.helper.d.ts +17 -0
  28. package/dist/opportunity/discovery-question.helper.d.ts.map +1 -0
  29. package/dist/opportunity/discovery-question.helper.js +27 -0
  30. package/dist/opportunity/discovery-question.helper.js.map +1 -0
  31. package/dist/opportunity/negotiation-summary.builder.d.ts +38 -0
  32. package/dist/opportunity/negotiation-summary.builder.d.ts.map +1 -0
  33. package/dist/opportunity/negotiation-summary.builder.js +67 -0
  34. package/dist/opportunity/negotiation-summary.builder.js.map +1 -0
  35. package/dist/opportunity/opportunity.discover.d.ts +22 -0
  36. package/dist/opportunity/opportunity.discover.d.ts.map +1 -1
  37. package/dist/opportunity/opportunity.discover.js +113 -0
  38. package/dist/opportunity/opportunity.discover.js.map +1 -1
  39. package/dist/opportunity/opportunity.enricher.d.ts +3 -2
  40. package/dist/opportunity/opportunity.enricher.d.ts.map +1 -1
  41. package/dist/opportunity/opportunity.enricher.js +1 -1
  42. package/dist/opportunity/opportunity.enricher.js.map +1 -1
  43. package/dist/opportunity/opportunity.graph.d.ts +20 -0
  44. package/dist/opportunity/opportunity.graph.d.ts.map +1 -1
  45. package/dist/opportunity/opportunity.graph.js +86 -44
  46. package/dist/opportunity/opportunity.graph.js.map +1 -1
  47. package/dist/opportunity/opportunity.state.d.ts +13 -0
  48. package/dist/opportunity/opportunity.state.d.ts.map +1 -1
  49. package/dist/opportunity/opportunity.state.js +18 -0
  50. package/dist/opportunity/opportunity.state.js.map +1 -1
  51. package/dist/opportunity/opportunity.tools.d.ts.map +1 -1
  52. package/dist/opportunity/opportunity.tools.js +13 -0
  53. package/dist/opportunity/opportunity.tools.js.map +1 -1
  54. package/dist/shared/agent/tool.factory.d.ts.map +1 -1
  55. package/dist/shared/agent/tool.factory.js +2 -0
  56. package/dist/shared/agent/tool.factory.js.map +1 -1
  57. package/dist/shared/agent/tool.helpers.d.ts +7 -0
  58. package/dist/shared/agent/tool.helpers.d.ts.map +1 -1
  59. package/dist/shared/agent/tool.helpers.js.map +1 -1
  60. package/dist/shared/interfaces/database.interface.d.ts +18 -40
  61. package/dist/shared/interfaces/database.interface.d.ts.map +1 -1
  62. package/dist/shared/interfaces/question-generator.interface.d.ts +18 -0
  63. package/dist/shared/interfaces/question-generator.interface.d.ts.map +1 -0
  64. package/dist/shared/interfaces/question-generator.interface.js +2 -0
  65. package/dist/shared/interfaces/question-generator.interface.js.map +1 -0
  66. package/package.json +1 -1
@@ -22,6 +22,7 @@ import { persistOpportunities } from './opportunity.persist.js';
22
22
  import { INTRODUCER_DISCOVERY_SOURCE } from './opportunity.introducer.js';
23
23
  import { negotiateCandidates } from "../negotiation/negotiation.graph.js";
24
24
  import { AMBIENT_PARK_WINDOW_MS } from "../negotiation/negotiation.tools.js";
25
+ import { buildDiscoverySummary, toDiscoveryNegotiation, } from "./negotiation-summary.builder.js";
25
26
  import { protocolLogger, withCallLogging } from '../shared/observability/protocol.logger.js';
26
27
  import { timed } from '../shared/observability/performance.js';
27
28
  import { requestContext } from "../shared/observability/request-context.js";
@@ -1621,56 +1622,79 @@ export class OpportunityGraphFactory {
1621
1622
  timeoutMs,
1622
1623
  candidateCount: candidates.length,
1623
1624
  });
1624
- // Orchestrator-only: per-candidate streaming hook. Each accepted
1625
- // negotiation flips the opp from 'pending' (negotiation finalize's
1626
- // default) to 'draft' (chat-only surface) and pushes an
1625
+ // Per-candidate hook — always-on. Accumulates negotiation resolutions
1626
+ // for discovery question generation. Additionally, for the orchestrator
1627
+ // trigger: flips the opp from 'pending' to 'draft' and pushes an
1627
1628
  // `opportunity_draft_ready` event so the frontend can render it
1628
1629
  // inline as soon as it resolves, rather than waiting for the full
1629
1630
  // fan-out. Abort (e.g. user closed the chat) suppresses both the
1630
1631
  // status flip and the event — the in-flight negotiation finishes
1631
1632
  // naturally but its card never reaches the user.
1632
- const onCandidateResolved = isOrchestrator
1633
- ? async ({ candidate, accepted }) => {
1634
- const abortSignal = requestContext.getStore()?.abortSignal;
1635
- if (abortSignal?.aborted)
1636
- return;
1637
- if (!accepted || !candidate.opportunityId)
1638
- return;
1639
- // Only emit after a successful status flip the frontend keys
1640
- // cards off `opportunity.status === 'draft'`, so emitting a row
1641
- // with its pre-flip status would render inconsistently. If the
1642
- // flip fails we log and drop the event; the negotiation result
1643
- // is still captured in acceptedResults for the final summary.
1644
- const updated = await this.database
1645
- .updateOpportunityStatus(candidate.opportunityId, 'draft')
1646
- .catch((err) => {
1647
- logger.warn('[Graph:Negotiate] failed to flip opp to draft; suppressing draft-ready event', {
1648
- opportunityId: candidate.opportunityId,
1649
- error: err,
1650
- });
1651
- return null;
1652
- });
1653
- if (!updated || abortSignal?.aborted)
1654
- return;
1655
- traceEmitter?.({
1656
- type: 'opportunity_draft_ready',
1633
+ // Build a stable order index so that resolutions accumulated via the
1634
+ // per-candidate async hook can be re-sorted to candidate-list order
1635
+ // before being handed to buildQuestionPrompt. Without this the LLM
1636
+ // sees negotiations in completion-time order (non-deterministic).
1637
+ const candidateOrderById = new Map();
1638
+ candidates.forEach((c, i) => candidateOrderById.set(c.userId, i));
1639
+ const resolutions = [];
1640
+ const onCandidateResolved = async ({ candidate, accepted, turns, outcome }) => {
1641
+ resolutions.push({
1642
+ __order: candidateOrderById.get(candidate.userId) ?? Number.MAX_SAFE_INTEGER,
1643
+ candidateUserId: candidate.userId,
1644
+ counterpartyHint: (() => {
1645
+ const bio = candidate.candidateUser.profile?.bio?.trim();
1646
+ if (bio)
1647
+ return bio;
1648
+ return (candidate.candidateUser.profile?.interests ?? []).join(", ");
1649
+ })(),
1650
+ indexContext: candidate.networkId
1651
+ ? indexContextMap.get(candidate.networkId) ?? ""
1652
+ : "",
1653
+ turns,
1654
+ outcome,
1655
+ });
1656
+ if (state.trigger !== 'orchestrator')
1657
+ return;
1658
+ // ─── orchestrator streaming body ───
1659
+ const abortSignal = requestContext.getStore()?.abortSignal;
1660
+ if (abortSignal?.aborted)
1661
+ return;
1662
+ if (!accepted || !candidate.opportunityId)
1663
+ return;
1664
+ // Only emit after a successful status flip — the frontend keys
1665
+ // cards off `opportunity.status === 'draft'`, so emitting a row
1666
+ // with its pre-flip status would render inconsistently. If the
1667
+ // flip fails we log and drop the event; the negotiation result
1668
+ // is still captured in acceptedResults for the final summary.
1669
+ const updated = await this.database
1670
+ .updateOpportunityStatus(candidate.opportunityId, 'draft')
1671
+ .catch((err) => {
1672
+ logger.warn('[Graph:Negotiate] failed to flip opp to draft; suppressing draft-ready event', {
1657
1673
  opportunityId: candidate.opportunityId,
1658
- opportunity: updated,
1659
- counterparty: {
1660
- userId: candidate.candidateUser.id,
1661
- ...(candidate.candidateUser.profile?.name
1662
- ? { name: candidate.candidateUser.profile.name }
1663
- : {}),
1664
- },
1674
+ error: err,
1665
1675
  });
1666
- }
1667
- : undefined;
1676
+ return null;
1677
+ });
1678
+ if (!updated || abortSignal?.aborted)
1679
+ return;
1680
+ traceEmitter?.({
1681
+ type: 'opportunity_draft_ready',
1682
+ opportunityId: candidate.opportunityId,
1683
+ opportunity: updated,
1684
+ counterparty: {
1685
+ userId: candidate.candidateUser.id,
1686
+ ...(candidate.candidateUser.profile?.name
1687
+ ? { name: candidate.candidateUser.profile.name }
1688
+ : {}),
1689
+ },
1690
+ });
1691
+ };
1668
1692
  const negotiationWork = negotiateCandidates(this.negotiationGraph, sourceUser, candidates, { networkId: '', prompt: '' }, // base context, overridden per-candidate below
1669
1693
  { maxTurns, traceEmitter: traceEmitter ?? undefined,
1670
1694
  indexContextOverrides: indexContextMap,
1671
1695
  timeoutMs,
1672
1696
  trigger: state.trigger === 'orchestrator' ? 'orchestrator' : 'ambient',
1673
- ...(onCandidateResolved && { onCandidateResolved }) });
1697
+ onCandidateResolved });
1674
1698
  // MCP-only: race the whole negotiate phase against a budget. When the
1675
1699
  // timer wins we return early with a `timed_out` trace; the unresolved
1676
1700
  // promise keeps running in the Bun event loop and each candidate's
@@ -1710,6 +1734,11 @@ export class OpportunityGraphFactory {
1710
1734
  negotiateTimeoutMs: budgetMs,
1711
1735
  });
1712
1736
  traceEmitter?.({ type: "graph_end", name: "Negotiation graph", durationMs: Date.now() - graphStart });
1737
+ const orderedResolutionsPartial = [...resolutions]
1738
+ .sort((a, b) => a.__order - b.__order)
1739
+ .map(({ __order: _o, ...r }) => r);
1740
+ const discoveryNegotiationsPartial = orderedResolutionsPartial.map(toDiscoveryNegotiation);
1741
+ const discoverySummaryPartial = buildDiscoverySummary(orderedResolutionsPartial);
1713
1742
  return {
1714
1743
  trace: [{
1715
1744
  node: 'negotiate',
@@ -1720,6 +1749,8 @@ export class OpportunityGraphFactory {
1720
1749
  durationMs: Date.now() - graphStart,
1721
1750
  },
1722
1751
  }],
1752
+ discoveryNegotiations: discoveryNegotiationsPartial,
1753
+ discoverySummary: discoverySummaryPartial,
1723
1754
  };
1724
1755
  }
1725
1756
  acceptedResults = raced;
@@ -1765,7 +1796,16 @@ export class OpportunityGraphFactory {
1765
1796
  ...candidateTraceEntries,
1766
1797
  ];
1767
1798
  traceEmitter?.({ type: "graph_end", name: "Negotiation graph", durationMs: Date.now() - graphStart });
1768
- return { trace: negotiateTrace };
1799
+ const orderedResolutions = [...resolutions]
1800
+ .sort((a, b) => a.__order - b.__order)
1801
+ .map(({ __order: _o, ...r }) => r);
1802
+ const discoveryNegotiations = orderedResolutions.map(toDiscoveryNegotiation);
1803
+ const discoverySummary = buildDiscoverySummary(orderedResolutions);
1804
+ return {
1805
+ trace: negotiateTrace,
1806
+ discoveryNegotiations,
1807
+ discoverySummary,
1808
+ };
1769
1809
  }
1770
1810
  catch (err) {
1771
1811
  logger.error("[Graph:Negotiate] Negotiation stage failed", { error: err });
@@ -1776,6 +1816,8 @@ export class OpportunityGraphFactory {
1776
1816
  detail: 'Negotiation failed',
1777
1817
  data: { durationMs: Date.now() - graphStart, error: true },
1778
1818
  }],
1819
+ discoveryNegotiations: [],
1820
+ discoverySummary: buildDiscoverySummary([]),
1779
1821
  };
1780
1822
  }
1781
1823
  };
@@ -2067,9 +2109,9 @@ export class OpportunityGraphFactory {
2067
2109
  }
2068
2110
  const lookups = await Promise.all([...uniqueCounterparts].map(async (counterpartyUserId) => {
2069
2111
  const accepted = await this.database
2070
- .getAcceptedOpportunitiesBetweenActors(dedupUserId, counterpartyUserId)
2112
+ .findOpportunitiesByActors([dedupUserId, counterpartyUserId], { includeIntroducers: true, statuses: ['accepted'] })
2071
2113
  .catch((err) => {
2072
- logger.warn('[Graph:Persist] getAcceptedOpportunitiesBetweenActors failed', {
2114
+ logger.warn('[Graph:Persist] findOpportunitiesByActors (sibling-accept) failed', {
2073
2115
  userId: dedupUserId,
2074
2116
  counterpartyUserId,
2075
2117
  error: err,
@@ -2164,7 +2206,7 @@ export class OpportunityGraphFactory {
2164
2206
  ];
2165
2207
  const candidateUserId = evaluated.actors.find((a) => a.userId !== state.onBehalfOfUserId)?.userId;
2166
2208
  const overlapping = candidateUserId
2167
- ? await this.database.findOverlappingOpportunities([state.onBehalfOfUserId, candidateUserId], { excludeStatuses: DEDUP_SKIP_STATUSES })
2209
+ ? await this.database.findOpportunitiesByActors([state.onBehalfOfUserId, candidateUserId], { excludeStatuses: DEDUP_SKIP_STATUSES })
2168
2210
  : [];
2169
2211
  if (overlapping.length > 0) {
2170
2212
  const existing = overlapping[0];
@@ -2283,9 +2325,9 @@ export class OpportunityGraphFactory {
2283
2325
  evaluatedActors: evaluated.actors.map(a => ({ userId: a.userId, role: a.role })),
2284
2326
  });
2285
2327
  const overlapping = candidateUserId
2286
- ? await this.database.findOverlappingOpportunities([state.userId, candidateUserId], { excludeStatuses: DEDUP_SKIP_STATUSES })
2328
+ ? await this.database.findOpportunitiesByActors([state.userId, candidateUserId], { excludeStatuses: DEDUP_SKIP_STATUSES })
2287
2329
  : [];
2288
- logger.verbose('[Graph:Persist:Dedup] findOverlappingOpportunities result', {
2330
+ logger.verbose('[Graph:Persist:Dedup] findOpportunitiesByActors result', {
2289
2331
  count: overlapping.length,
2290
2332
  results: overlapping.map(o => ({ id: o.id, status: o.status, actors: o.actors?.map((a) => ({ userId: a.userId, role: a.role })) })),
2291
2333
  });