@indexnetwork/protocol 4.11.0-rc.351.1 → 4.13.0-rc.353.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 (53) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/index.d.ts +3 -3
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/intent/intent.graph.d.ts +12 -5
  7. package/dist/intent/intent.graph.d.ts.map +1 -1
  8. package/dist/intent/intent.graph.js +19 -6
  9. package/dist/intent/intent.graph.js.map +1 -1
  10. package/dist/opportunity/discriminator/discriminator.question.d.ts +2 -0
  11. package/dist/opportunity/discriminator/discriminator.question.d.ts.map +1 -1
  12. package/dist/opportunity/discriminator/discriminator.question.js +3 -0
  13. package/dist/opportunity/discriminator/discriminator.question.js.map +1 -1
  14. package/dist/opportunity/discriminator/discriminator.shadow.d.ts +8 -0
  15. package/dist/opportunity/discriminator/discriminator.shadow.d.ts.map +1 -1
  16. package/dist/opportunity/discriminator/discriminator.shadow.js +41 -7
  17. package/dist/opportunity/discriminator/discriminator.shadow.js.map +1 -1
  18. package/dist/opportunity/discriminator/discriminator.types.d.ts +4 -0
  19. package/dist/opportunity/discriminator/discriminator.types.d.ts.map +1 -1
  20. package/dist/opportunity/discriminator/discriminator.types.js.map +1 -1
  21. package/dist/opportunity/opportunity.pending-questions.d.ts.map +1 -1
  22. package/dist/opportunity/opportunity.pending-questions.js +2 -1
  23. package/dist/opportunity/opportunity.pending-questions.js.map +1 -1
  24. package/dist/opportunity/opportunity.tools.d.ts.map +1 -1
  25. package/dist/opportunity/opportunity.tools.js +85 -3
  26. package/dist/opportunity/opportunity.tools.js.map +1 -1
  27. package/dist/questioner/questioner.env.d.ts +9 -0
  28. package/dist/questioner/questioner.env.d.ts.map +1 -1
  29. package/dist/questioner/questioner.env.js +19 -0
  30. package/dist/questioner/questioner.env.js.map +1 -1
  31. package/dist/questioner/questioner.presets.d.ts.map +1 -1
  32. package/dist/questioner/questioner.presets.js +44 -4
  33. package/dist/questioner/questioner.presets.js.map +1 -1
  34. package/dist/questioner/questioner.tools.d.ts.map +1 -1
  35. package/dist/questioner/questioner.tools.js +3 -3
  36. package/dist/questioner/questioner.tools.js.map +1 -1
  37. package/dist/questioner/questioner.types.d.ts +37 -8
  38. package/dist/questioner/questioner.types.d.ts.map +1 -1
  39. package/dist/questioner/questioner.types.js.map +1 -1
  40. package/dist/shared/agent/tool.helpers.d.ts +4 -1
  41. package/dist/shared/agent/tool.helpers.d.ts.map +1 -1
  42. package/dist/shared/agent/tool.helpers.js.map +1 -1
  43. package/dist/shared/interfaces/questioner.interface.d.ts +2 -1
  44. package/dist/shared/interfaces/questioner.interface.d.ts.map +1 -1
  45. package/dist/shared/interfaces/questioner.interface.js.map +1 -1
  46. package/dist/shared/schemas/pending-question.schema.d.ts +3 -1
  47. package/dist/shared/schemas/pending-question.schema.d.ts.map +1 -1
  48. package/dist/shared/schemas/pending-question.schema.js.map +1 -1
  49. package/dist/shared/schemas/question.schema.d.ts +81 -0
  50. package/dist/shared/schemas/question.schema.d.ts.map +1 -1
  51. package/dist/shared/schemas/question.schema.js +10 -0
  52. package/dist/shared/schemas/question.schema.js.map +1 -1
  53. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"discriminator.types.d.ts","sourceRoot":"/","sources":["opportunity/discriminator/discriminator.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0CAA0C;AAC1C,MAAM,WAAW,wBAAwB;IACvC,gFAAgF;IAChF,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,yEAAyE;AACzE,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4CAA4C;IAC5C,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,yEAAyE;AACzE,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wEAAwE;AACxE,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,cAAc,EAAE,mBAAmB,EAAE,CAAC;CACvC"}
1
+ {"version":3,"file":"discriminator.types.d.ts","sourceRoot":"/","sources":["opportunity/discriminator/discriminator.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0CAA0C;AAC1C,MAAM,WAAW,wBAAwB;IACvC,gFAAgF;IAChF,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,yEAAyE;AACzE,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4CAA4C;IAC5C,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,yEAAyE;AACzE,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wEAAwE;AACxE,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,cAAc,EAAE,mBAAmB,EAAE,CAAC;CACvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"discriminator.types.js","sourceRoot":"/","sources":["opportunity/discriminator/discriminator.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG","sourcesContent":["/**\n * Pool discriminator mining — shared types (IND-416 / IND-417).\n *\n * A \"pool discriminator\" is a preference dimension that splits a discovery-run\n * candidate pool into meaningfully different groups (e.g. \"hands-on builders\n * vs advisors\"). Discriminators are mined by one structured LLM pass, then\n * scored deterministically (VoI = entropy × coverage^1.5 × novelty) so the\n * highest value question can eventually be asked to the intent owner.\n *\n * Vocabulary note: the LLM wire format (prompt + response schema in the miner)\n * speaks of \"axes\" with mutually exclusive \"sides\" — the clearest way to\n * explain the concept to the model. Everything the rest of the codebase\n * touches (types, exports, logs) uses \"discriminator\".\n *\n * P1 (shadow) uses these types for log-only output; later phases reuse them\n * for question synthesis and answer application.\n */\n\n/** One candidate in the pool as supplied to the miner LLM. */\nexport interface PoolCandidate {\n /** Opportunity id (stable key for later answer application). */\n id: string;\n /**\n * The exact public-context string shown to the LLM for this candidate\n * (name + bio + matchReason + headline + premise snippets, ≤400 chars).\n * Evidence spans are substring-verified against this exact string.\n */\n publicContext: string;\n /** Candidate confidence/score — the mass used for score-weighted entropy. */\n score: number;\n}\n\n/** Input envelope for one mining pass. */\nexport interface DiscriminatorMiningInput {\n /** Intent payload (+ summary) or ad-hoc search query that produced the pool. */\n intentText: string;\n candidates: PoolCandidate[];\n}\n\n/**\n * One candidate assignment on a discriminator, after code-side evidence verification.\n * `side === null` means unknown (LLM abstained, evidence failed verification,\n * or the candidate was missing from the LLM output).\n */\nexport interface VerifiedAssignment {\n /** Candidate (opportunity) id. */\n id: string;\n /** Verified side label (one of the discriminator's sides), or null = unknown. */\n side: string | null;\n /** The evidence span quoted by the LLM (kept for logging/audit), if any. */\n evidence: string | null;\n /**\n * True when the LLM proposed a side AND its evidence span substring-matched\n * the candidate's publicContext. False for demoted-to-unknown proposals.\n */\n verified: boolean;\n}\n\n/** One mined discriminator after evidence verification (pre-scoring). */\nexport interface MinedDiscriminator {\n /** Short discriminator label, e.g. \"Hands-on builders vs strategic advisors\". */\n label: string;\n /** A question the intent owner could be asked to resolve the discriminator. */\n questionSeed: string;\n /** 2–3 mutually exclusive side labels. */\n sides: string[];\n /** Exactly one entry per pool candidate. */\n assignments: VerifiedAssignment[];\n /**\n * verified-proposals / total side proposals from the LLM for this discriminator\n * (0 when the LLM proposed no sides at all). The hallucination health metric.\n */\n evidenceRate: number;\n}\n\n/** A mined discriminator with its deterministic VoI score components. */\nexport interface ScoredDiscriminator extends MinedDiscriminator {\n /** Normalized score-weighted entropy over sides, in [0,1]. */\n entropy: number;\n /** Assigned score mass / total pool score mass, in [0,1]. */\n coverage: number;\n /** 1 − max cosine similarity vs reference texts (premises/intent), in [0,1]. */\n novelty: number;\n /** entropy × coverage^1.5 × novelty. */\n voi: number;\n}\n\n/** Result of one shadow mining+scoring pass (the log payload shape). */\nexport interface DiscriminatorShadowResult {\n poolSize: number;\n /** Scored discriminators, sorted by VoI descending. */\n discriminators: ScoredDiscriminator[];\n}\n"]}
1
+ {"version":3,"file":"discriminator.types.js","sourceRoot":"/","sources":["opportunity/discriminator/discriminator.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG","sourcesContent":["/**\n * Pool discriminator mining — shared types (IND-416 / IND-417).\n *\n * A \"pool discriminator\" is a preference dimension that splits a discovery-run\n * candidate pool into meaningfully different groups (e.g. \"hands-on builders\n * vs advisors\"). Discriminators are mined by one structured LLM pass, then\n * scored deterministically (VoI = entropy × coverage^1.5 × novelty) so the\n * highest value question can eventually be asked to the intent owner.\n *\n * Vocabulary note: the LLM wire format (prompt + response schema in the miner)\n * speaks of \"axes\" with mutually exclusive \"sides\" — the clearest way to\n * explain the concept to the model. Everything the rest of the codebase\n * touches (types, exports, logs) uses \"discriminator\".\n *\n * P1 (shadow) uses these types for log-only output; later phases reuse them\n * for question synthesis and answer application.\n */\n\n/** One candidate in the pool as supplied to the miner LLM. */\nexport interface PoolCandidate {\n /** Opportunity id (stable key for later answer application). */\n id: string;\n /**\n * The exact public-context string shown to the LLM for this candidate\n * (name + bio + matchReason + headline + premise snippets, ≤400 chars).\n * Evidence spans are substring-verified against this exact string.\n */\n publicContext: string;\n /** Candidate confidence/score — the mass used for score-weighted entropy. */\n score: number;\n}\n\n/** Input envelope for one mining pass. */\nexport interface DiscriminatorMiningInput {\n /** Intent payload (+ summary) or ad-hoc search query that produced the pool. */\n intentText: string;\n candidates: PoolCandidate[];\n}\n\n/**\n * One candidate assignment on a discriminator, after code-side evidence verification.\n * `side === null` means unknown (LLM abstained, evidence failed verification,\n * or the candidate was missing from the LLM output).\n */\nexport interface VerifiedAssignment {\n /** Candidate (opportunity) id. */\n id: string;\n /** Verified side label (one of the discriminator's sides), or null = unknown. */\n side: string | null;\n /** The evidence span quoted by the LLM (kept for logging/audit), if any. */\n evidence: string | null;\n /**\n * True when the LLM proposed a side AND its evidence span substring-matched\n * the candidate's publicContext. False for demoted-to-unknown proposals.\n */\n verified: boolean;\n}\n\n/** One mined discriminator after evidence verification (pre-scoring). */\nexport interface MinedDiscriminator {\n /** Short discriminator label, e.g. \"Hands-on builders vs strategic advisors\". */\n label: string;\n /** A question the intent owner could be asked to resolve the discriminator. */\n questionSeed: string;\n /** 2–3 mutually exclusive side labels. */\n sides: string[];\n /** Exactly one entry per pool candidate. */\n assignments: VerifiedAssignment[];\n /**\n * verified-proposals / total side proposals from the LLM for this discriminator\n * (0 when the LLM proposed no sides at all). The hallucination health metric.\n */\n evidenceRate: number;\n}\n\n/** A mined discriminator with its deterministic VoI score components. */\nexport interface ScoredDiscriminator extends MinedDiscriminator {\n /** Current discriminator embedding retained for durable semantic dedup. */\n embedding?: number[];\n /** Model that generated {@link embedding}. */\n embeddingModel?: string;\n /** Normalized score-weighted entropy over sides, in [0,1]. */\n entropy: number;\n /** Assigned score mass / total pool score mass, in [0,1]. */\n coverage: number;\n /** 1 − max cosine similarity vs reference texts (premises/intent), in [0,1]. */\n novelty: number;\n /** entropy × coverage^1.5 × novelty. */\n voi: number;\n}\n\n/** Result of one shadow mining+scoring pass (the log payload shape). */\nexport interface DiscriminatorShadowResult {\n poolSize: number;\n /** Scored discriminators, sorted by VoI descending. */\n discriminators: ScoredDiscriminator[];\n}\n"]}
@@ -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,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,QAAQ,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAC7G,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,sCAAsC;IACtC,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,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,CA+BtC"}
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,CAAC;QAAC,SAAS,CAAC,EAAE,QAAQ,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAC7G,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,sCAAsC;IACtC,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,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,CAgCtC"}
@@ -34,8 +34,9 @@ export async function mergePendingQuestions(input) {
34
34
  // Deduplicate against already-surfaced IDs in this session
35
35
  const fresh = pending.filter((q) => !input.surfacedQuestionIds.has(q.id));
36
36
  const capped = fresh.slice(0, MAX_PENDING_QUESTIONS);
37
+ const publicQuestions = capped.map(({ actors: _actors, purpose: _purpose, ...question }) => question);
37
38
  return {
38
- questions: capped,
39
+ questions: publicQuestions,
39
40
  surfacedIds: capped.map((q) => q.id),
40
41
  };
41
42
  }
@@ -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;AA0BvC;;;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,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;IACnF,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;YAC1D,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpG;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; scopeType?: 'intent'; scopeId?: 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 /** Optional selected-intent scope. */\n scopeType?: 'intent';\n scopeId?: 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 || input.scopeType);\n const filters = hasFilters\n ? {\n ...(input.sourceType ? { sourceType: input.sourceType } : {}),\n ...(input.sourceId ? { sourceId: input.sourceId } : {}),\n ...(input.networkId ? { networkId: input.networkId } : {}),\n ...(input.scopeType && input.scopeId ? { scopeType: input.scopeType, scopeId: input.scopeId } : {}),\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"]}
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;AA0BvC;;;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,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;IACnF,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;YAC1D,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpG;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;IACrD,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;IAEtG,OAAO;QACL,SAAS,EAAE,eAAe;QAC1B,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; scopeType?: 'intent'; scopeId?: 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 /** Optional selected-intent scope. */\n scopeType?: 'intent';\n scopeId?: 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 || input.scopeType);\n const filters = hasFilters\n ? {\n ...(input.sourceType ? { sourceType: input.sourceType } : {}),\n ...(input.sourceId ? { sourceId: input.sourceId } : {}),\n ...(input.networkId ? { networkId: input.networkId } : {}),\n ...(input.scopeType && input.scopeId ? { scopeType: input.scopeType, scopeId: input.scopeId } : {}),\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 const publicQuestions = capped.map(({ actors: _actors, purpose: _purpose, ...question }) => question);\n\n return {\n questions: publicQuestions,\n surfacedIds: capped.map((q) => q.id),\n };\n}\n"]}
@@ -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":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAiC5E,OAAO,KAAK,EAAE,WAAW,EAAqB,MAAM,4CAA4C,CAAC;AAGjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAC;AAQtF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,GAAG,eAAe,GAAG,IAAI,CAezB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,iBAAiB,EAAE,MAAM,EACzB,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,MAAM,GAAG,SAAS,CAQpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,MAAM,GAAG,SAAS,CAIpB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,EACD,IAAI,EAAE;IACJ,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,WAAW,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC1D,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,gBAAgB,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC;CACvC,GACA,OAAO,CAAC,IAAI,CAAC,CA+Cf;AAwFD;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,MAAM,EACzB,eAAe,EAAE,MAAM,EACvB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,EAC9B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,EAChC,UAAU,CAAC,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,MAAM,EACxB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,EACjC,iBAAiB,CAAC,EAAE,MAAM,EAC1B,kBAAkB,CAAC,EAAE,OAAO,GAC3B;IACD,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACzE,CA8DA;AAED;;;;GAIG;AACH,KAAK,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAClC,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,mBAAmB,EAAE,EAC5B,IAAI,EAAE;IACJ,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,GAAG,eAAe,CAAC;IACxC,8FAA8F;IAC9F,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,GACA,MAAM,CA2DR;AAuDD;;;;;;;;;GASG;AACH,MAAM,MAAM,wBAAwB,GAChC,iBAAiB,GACjB,oBAAoB,GACpB,wBAAwB,GACxB,uBAAuB,GACvB,gBAAgB,GAChB,gBAAgB,CAAC;AAUrB,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,2CAg8D5E"}
@@ -6,7 +6,7 @@ import { MINIMAL_MAIN_TEXT_MAX_CHARS, getPrimaryActionLabel, SECONDARY_ACTION_LA
6
6
  import { narratorRemarkFromReasoning, stripUuids } from "./opportunity.presentation.js";
7
7
  import { safeFallbackSummary, getSafePresentationOrSkip } from "./opportunity.safe-presentation.js";
8
8
  import { runDiscoverFromQuery, continueDiscovery } from "./opportunity.discover.js";
9
- import { isDiscoveryQuestionsEnabled } from "../questioner/questioner.env.js";
9
+ import { isDiscoveryQuestionsEnabled, isUptakeGuardEnabled } from "../questioner/questioner.env.js";
10
10
  import { OpportunityPresenter, gatherPresenterContext } from "./opportunity.presenter.js";
11
11
  import { loadNegotiationContext } from "./negotiation-context.loader.js";
12
12
  function stripLeadingNarratorName(remark, narratorName) {
@@ -183,6 +183,28 @@ const UPDATE_OPPORTUNITY_BLOCKED_STATUSES = new Set([
183
183
  "expired",
184
184
  "negotiating",
185
185
  ]);
186
+ function publicUptakeQuestion(question) {
187
+ return {
188
+ id: question.id,
189
+ title: question.title,
190
+ prompt: question.prompt,
191
+ options: question.options,
192
+ multiSelect: question.multiSelect,
193
+ };
194
+ }
195
+ function uptakeAdvisory(opportunityId, questions) {
196
+ return JSON.stringify({
197
+ success: false,
198
+ error: "Resolve the pending uptake questions or explicitly continue anyway.",
199
+ advisory: {
200
+ code: "unresolved_uptake_questions",
201
+ advisoryOnly: true,
202
+ opportunityId,
203
+ questions,
204
+ acknowledgedUptakeQuestionIds: questions.map((question) => question.id),
205
+ },
206
+ });
207
+ }
186
208
  function matchesSelectedIntentScope(opportunity, viewerId, scope) {
187
209
  if (scope?.scopeType !== 'intent' || !scope.scopeId)
188
210
  return true;
@@ -1917,8 +1939,9 @@ export function createOpportunityTools(defineTool, deps) {
1917
1939
  "- `rejected`: Decline a received opportunity.\n" +
1918
1940
  "- `expired`: Mark as expired (typically done by the system after timeout).\n\n" +
1919
1941
  "**When to use:** After discover_opportunities or list_opportunities returns opportunity cards. " +
1920
- "The user clicks 'Send' (pending), 'Accept', or 'Reject' on the card, and the agent calls this tool.\n\n" +
1921
- "**Returns:** Confirmation with the new status and notification details (who was notified).",
1942
+ "The user clicks 'Send' (pending), 'Accept', or 'Reject' on the card, and the agent calls this tool. " +
1943
+ "An accepted transition may first return a non-success uptake advisory with preparatory questions. Surface those questions, then retry with all returned question ids in acknowledgedUptakeQuestionIds; acknowledgement confirms presentation, not an answer.\n\n" +
1944
+ "**Returns:** Confirmation with the new status and notification details (who was notified), or a structured uptake advisory without mutation.",
1922
1945
  querySchema: z.object({
1923
1946
  opportunityId: z
1924
1947
  .string()
@@ -1927,6 +1950,10 @@ export function createOpportunityTools(defineTool, deps) {
1927
1950
  .enum(["pending", "accepted", "rejected", "expired"])
1928
1951
  .describe("New status: 'pending' = send the draft to the other party, 'accepted' = accept the connection, " +
1929
1952
  "'rejected' = decline, 'expired' = mark as timed out."),
1953
+ acknowledgedUptakeQuestionIds: z
1954
+ .array(z.string().min(1))
1955
+ .optional()
1956
+ .describe("On an acknowledged retry after an uptake advisory, include every question id returned by that advisory."),
1930
1957
  scopeType: z
1931
1958
  .enum(['intent'])
1932
1959
  .optional()
@@ -1991,6 +2018,61 @@ export function createOpportunityTools(defineTool, deps) {
1991
2018
  if (!matchesSelectedIntentScope(opportunity, context.userId, effectiveIntentScope)) {
1992
2019
  return error("Opportunity not found.");
1993
2020
  }
2021
+ // The caller actor's own network is the exact question lookup boundary,
2022
+ // even for an otherwise unscoped request. A focused network may only be
2023
+ // equal to this after the guard above.
2024
+ // Unscoped callers query all of their exact opportunity questions; a
2025
+ // network-scoped caller is clamped to the bound network. Selecting the
2026
+ // first duplicate actor row would miss a valid question on another
2027
+ // shared network.
2028
+ const uptakeNetworkId = scopedNetworkId;
2029
+ // Soft uptake interlock: only acceptance is advisory-gated. All existing
2030
+ // actor/scope/privacy guards run first so the question lookup cannot be
2031
+ // used to probe opportunities or networks the caller cannot access.
2032
+ if (query.status === "accepted" && isUptakeGuardEnabled() && deps.findPendingQuestions) {
2033
+ try {
2034
+ const pending = await deps.findPendingQuestions(context.userId, {
2035
+ sourceType: "opportunity",
2036
+ sourceId: opportunityId,
2037
+ modes: ["negotiation"],
2038
+ purpose: "uptake",
2039
+ ...(uptakeNetworkId ? { networkId: uptakeNetworkId } : {}),
2040
+ });
2041
+ // Defense in depth if a host overlooks one or more filters. Actor
2042
+ // internals are checked here and never serialized into the advisory.
2043
+ const exactPending = pending.filter((question) => {
2044
+ if (question.sourceType !== "opportunity" ||
2045
+ question.sourceId !== opportunityId ||
2046
+ question.mode !== "negotiation" ||
2047
+ question.purpose !== "uptake") {
2048
+ return false;
2049
+ }
2050
+ if (!question.actors?.some((actor) => actor.userId === context.userId))
2051
+ return false;
2052
+ if (uptakeNetworkId && !question.actors.some((actor) => actor.userId === context.userId && actor.networkId === uptakeNetworkId)) {
2053
+ return false;
2054
+ }
2055
+ return true;
2056
+ });
2057
+ const acknowledged = new Set(query.acknowledgedUptakeQuestionIds ?? []);
2058
+ if (exactPending.some((question) => !acknowledged.has(question.id))) {
2059
+ return uptakeAdvisory(opportunityId, exactPending.map(publicUptakeQuestion));
2060
+ }
2061
+ }
2062
+ catch (err) {
2063
+ logger.warn("update_opportunity: uptake question lookup failed open", {
2064
+ opportunityId,
2065
+ userId: context.userId,
2066
+ error: err instanceof Error ? err.message : String(err),
2067
+ });
2068
+ deps.reportToolError?.(err, {
2069
+ subsystem: "opportunity",
2070
+ operation: "opportunity.uptake_lookup",
2071
+ toolName: "update_opportunity",
2072
+ userId: context.userId,
2073
+ });
2074
+ }
2075
+ }
1994
2076
  const isSend = query.status === "pending";
1995
2077
  const _updateGraphStart = Date.now();
1996
2078
  const _updateTraceEmitter = requestContext.getStore()?.traceEmitter;