@indexnetwork/protocol 22.0.0-rc.498.1 → 64.0.0-rc.604.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1841 -0
- package/IMPLEMENTATION.md +140 -181
- package/README.md +16 -20
- package/STABILITY.md +16 -11
- package/dist/{intents/intent.module.d.ts → capabilities/intents.d.ts} +182 -192
- package/dist/capabilities/intents.js +88 -0
- package/dist/capabilities/negotiations.d.ts +17 -0
- package/dist/capabilities/negotiations.js +16 -0
- package/dist/{networks/network.module.d.ts → capabilities/networks.d.ts} +33 -169
- package/dist/{networks/network.module.js → capabilities/networks.js} +6 -17
- package/dist/index.d.ts +57 -132
- package/dist/index.js +41 -100
- package/dist/internal/agents/agent.repository.port.d.ts +59 -0
- package/dist/internal/agents/agent.repository.port.js +7 -0
- package/dist/internal/agents/agent.types.d.ts +35 -0
- package/dist/{agents → internal/agents}/agent.types.js +1 -6
- package/dist/{intents → internal/intents}/graph/intent.graph.d.ts +142 -151
- package/dist/{intents → internal/intents}/graph/intent.graph.execute.d.ts +5 -1
- package/dist/{intents → internal/intents}/graph/intent.graph.execute.js +165 -46
- package/dist/internal/intents/graph/intent.graph.infer.d.ts +78 -0
- package/dist/internal/intents/graph/intent.graph.infer.js +122 -0
- package/dist/internal/intents/graph/intent.graph.js +108 -0
- package/dist/{intents → internal/intents}/graph/intent.graph.reconcile.d.ts +18 -9
- package/dist/internal/intents/graph/intent.graph.reconcile.js +173 -0
- package/dist/internal/intents/graph/intent.graph.shared.d.ts +55 -0
- package/dist/{intents → internal/intents}/graph/intent.graph.shared.js +25 -70
- package/dist/{intents → internal/intents}/graph/intent.graph.state.d.ts +96 -32
- package/dist/{intents → internal/intents}/graph/intent.graph.state.js +42 -31
- package/dist/internal/intents/intent.admission.d.ts +16 -0
- package/dist/internal/intents/intent.admission.js +30 -0
- package/dist/{intents → internal/intents}/intent.inferrer.d.ts +1 -40
- package/dist/{intents → internal/intents}/intent.inferrer.js +13 -49
- package/dist/internal/intents/intent.preparer.d.ts +52 -0
- package/dist/internal/intents/intent.preparer.js +87 -0
- package/dist/{intents → internal/intents}/intent.verifier.d.ts +3 -36
- package/dist/{intents → internal/intents}/intent.verifier.js +0 -17
- package/dist/{networks → internal/networks}/indexer.graph.d.ts +15 -200
- package/dist/{networks → internal/networks}/indexer.graph.js +19 -128
- package/dist/{networks → internal/networks}/indexer.state.d.ts +8 -63
- package/dist/internal/networks/indexer.state.js +70 -0
- package/dist/{networks → internal/networks}/membership.graph.d.ts +6 -6
- package/dist/{networks → internal/networks}/membership.graph.js +3 -3
- package/dist/{networks → internal/networks}/membership.state.d.ts +2 -2
- package/dist/{networks → internal/networks}/membership.state.js +2 -2
- package/dist/{networks → internal/networks}/network.graph.d.ts +9 -22
- package/dist/{networks → internal/networks}/network.graph.js +13 -27
- package/dist/{networks → internal/networks}/network.recommender.d.ts +2 -2
- package/dist/{networks → internal/networks}/network.recommender.js +2 -2
- package/dist/{networks → internal/networks}/network.state.d.ts +4 -7
- package/dist/{networks → internal/networks}/network.state.js +4 -4
- package/dist/internal/opportunities/negotiation-context.loader.d.ts +26 -0
- package/dist/internal/opportunities/negotiation-context.loader.js +36 -0
- package/dist/{opportunities → internal/opportunities}/opportunity.actor.d.ts +1 -1
- package/dist/{opportunities → internal/opportunities}/opportunity.actor.js +7 -1
- package/dist/internal/opportunities/opportunity.counterparties.d.ts +17 -0
- package/dist/internal/opportunities/opportunity.counterparties.js +19 -0
- package/dist/internal/opportunities/opportunity.events.d.ts +38 -0
- package/dist/internal/opportunities/opportunity.events.js +94 -0
- package/dist/{opportunities → internal/opportunities}/opportunity.feed-selection.d.ts +3 -9
- package/dist/internal/opportunities/opportunity.feed-selection.js +40 -0
- package/dist/internal/opportunities/opportunity.graph.modes.d.ts +39 -0
- package/dist/internal/opportunities/opportunity.graph.modes.js +138 -0
- package/dist/{opportunities → internal/opportunities}/opportunity.labels.d.ts +2 -3
- package/dist/internal/opportunities/opportunity.labels.js +9 -0
- package/dist/{opportunities → internal/opportunities}/opportunity.presentation.d.ts +17 -86
- package/dist/{opportunities → internal/opportunities}/opportunity.presentation.js +54 -447
- package/dist/{opportunities → internal/opportunities}/opportunity.update-admission.d.ts +2 -2
- package/dist/internal/opportunities/opportunity.utils.d.ts +105 -0
- package/dist/internal/opportunities/opportunity.utils.js +165 -0
- package/dist/{opportunities → internal/opportunities}/radar/radar.graph.d.ts +17 -17
- package/dist/{opportunities → internal/opportunities}/radar/radar.graph.js +41 -161
- package/dist/{opportunities → internal/opportunities}/radar/radar.state.d.ts +4 -11
- package/dist/{shared → internal/shared}/agent/model-signal.d.ts +1 -1
- package/dist/{shared → internal/shared}/agent/model-signal.js +1 -1
- package/dist/{shared → internal/shared}/agent/model.config.d.ts +28 -86
- package/dist/{shared → internal/shared}/agent/model.config.js +58 -69
- package/dist/internal/shared/agent/model.resolver.d.ts +33 -0
- package/dist/{shared → internal/shared}/agent/model.resolver.js +18 -33
- package/dist/internal/shared/agent/scope.d.ts +20 -0
- package/dist/internal/shared/agent/scope.js +24 -0
- package/dist/internal/shared/assignment/network-assignment.policy.d.ts +23 -0
- package/dist/internal/shared/assignment/network-assignment.policy.js +28 -0
- package/dist/{shared → internal/shared}/observability/log.d.ts +3 -6
- package/dist/{shared → internal/shared}/observability/log.js +9 -18
- package/dist/{shared → internal/shared}/observability/protocol.logger.d.ts +1 -1
- package/dist/{shared → internal/shared}/observability/protocol.logger.js +1 -1
- package/dist/internal/shared/observability/request-context.d.ts +29 -0
- package/dist/internal/shared/observability/request-context.js +17 -0
- package/dist/{shared → internal/shared}/utils/social-label.d.ts +2 -2
- package/dist/{shared → internal/shared}/utils/social-label.js +1 -1
- package/dist/platform/database/capabilities.d.ts +59 -0
- package/dist/{shared/interfaces/database.entities.d.ts → platform/database/entities.d.ts} +81 -121
- package/dist/{shared/interfaces/database.identity-queries.d.ts → platform/database/identity-queries.d.ts} +55 -20
- package/dist/platform/database/member-queries.d.ts +55 -0
- package/dist/platform/database/member-queries.js +4 -0
- package/dist/platform/database/negotiation.d.ts +38 -0
- package/dist/{shared/interfaces/database.network-queries.d.ts → platform/database/network-queries.d.ts} +66 -67
- package/dist/platform/database/network-queries.js +4 -0
- package/dist/{shared/interfaces/database.opportunity-queries.d.ts → platform/database/opportunity-queries.d.ts} +25 -109
- package/dist/{shared/interfaces/database.port.d.ts → platform/database/port.d.ts} +52 -117
- package/dist/{shared/interfaces/database.port.js → platform/database/port.js} +3 -5
- package/dist/platform/database.d.ts +23 -0
- package/dist/{shared/interfaces/database.interface.js → platform/database.js} +1 -1
- package/dist/{shared/interfaces/cache.interface.d.ts → platform/discovery/cache.d.ts} +2 -4
- package/dist/{shared/interfaces/cache.interface.js → platform/discovery/cache.js} +1 -1
- package/dist/platform/discovery/embedder.d.ts +31 -0
- package/dist/platform/runtime/errors.d.ts +6 -0
- package/dist/platform/runtime/errors.js +9 -0
- package/dist/platform/runtime/follow-up.d.ts +36 -0
- package/dist/platform/runtime/follow-up.js +4 -0
- package/dist/platform/runtime/observability.d.ts +34 -0
- package/dist/protocol/core.d.ts +11 -0
- package/dist/protocol/discovery.rules.d.ts +21 -0
- package/dist/protocol/discovery.rules.js +29 -0
- package/dist/protocol/negotiation.constants.d.ts +3 -0
- package/dist/protocol/negotiation.constants.js +3 -0
- package/dist/protocol/negotiation.rules.d.ts +73 -0
- package/dist/protocol/negotiation.rules.js +68 -0
- package/dist/protocol/protocol.prompt.d.ts +13 -0
- package/dist/protocol/protocol.prompt.js +190 -0
- package/dist/{shared → protocol}/schemas/discovery-question.schema.d.ts +13 -13
- package/dist/{shared → protocol}/schemas/discovery-question.schema.js +2 -2
- package/dist/{shared → protocol}/schemas/identity.schema.d.ts +4 -4
- package/dist/{shared → protocol}/schemas/identity.schema.js +4 -4
- package/dist/{shared → protocol}/schemas/network-assignment.schema.d.ts +11 -20
- package/dist/{shared → protocol}/schemas/network-assignment.schema.js +2 -9
- package/dist/protocol/schemas/underspecification.schema.d.ts +9 -0
- package/dist/protocol/schemas/underspecification.schema.js +12 -0
- package/package.json +7 -15
- package/dist/agents/agent.dispatcher.port.d.ts +0 -25
- package/dist/agents/agent.module.d.ts +0 -19
- package/dist/agents/agent.module.js +0 -11
- package/dist/agents/agent.repository.port.d.ts +0 -118
- package/dist/agents/agent.repository.port.js +0 -10
- package/dist/agents/agent.tools.d.ts +0 -16
- package/dist/agents/agent.tools.js +0 -351
- package/dist/agents/agent.tools.port.d.ts +0 -22
- package/dist/agents/agent.tools.port.js +0 -18
- package/dist/agents/agent.types.d.ts +0 -76
- package/dist/chat/chat-streaming.types.d.ts +0 -618
- package/dist/chat/chat-streaming.types.js +0 -297
- package/dist/chat/chat.agent.d.ts +0 -292
- package/dist/chat/chat.agent.js +0 -1010
- package/dist/chat/chat.graph.d.ts +0 -424
- package/dist/chat/chat.graph.js +0 -257
- package/dist/chat/chat.interrupt.classifier.d.ts +0 -25
- package/dist/chat/chat.interrupt.classifier.js +0 -64
- package/dist/chat/chat.persona.d.ts +0 -39
- package/dist/chat/chat.prompt.d.ts +0 -4
- package/dist/chat/chat.prompt.js +0 -12
- package/dist/chat/chat.prompt.modules.d.ts +0 -30
- package/dist/chat/chat.prompt.modules.js +0 -40
- package/dist/chat/chat.question-dedup.d.ts +0 -14
- package/dist/chat/chat.question-dedup.js +0 -17
- package/dist/chat/chat.state.d.ts +0 -135
- package/dist/chat/chat.state.js +0 -120
- package/dist/chat/chat.streamer.d.ts +0 -64
- package/dist/chat/chat.streamer.js +0 -217
- package/dist/chat/chat.suggester.d.ts +0 -23
- package/dist/chat/chat.suggester.js +0 -95
- package/dist/chat/chat.summarizer.d.ts +0 -20
- package/dist/chat/chat.summarizer.js +0 -97
- package/dist/chat/chat.title.generator.d.ts +0 -19
- package/dist/chat/chat.title.generator.js +0 -66
- package/dist/chat/chat.tools.d.ts +0 -5
- package/dist/chat/chat.tools.js +0 -62
- package/dist/chat/chat.utils.d.ts +0 -41
- package/dist/chat/chat.utils.js +0 -88
- package/dist/chat/negotiator.persona.d.ts +0 -74
- package/dist/chat/negotiator.persona.js +0 -154
- package/dist/chat/negotiator.prompt.d.ts +0 -45
- package/dist/chat/negotiator.prompt.js +0 -160
- package/dist/chat/negotiator.tools.d.ts +0 -42
- package/dist/chat/negotiator.tools.js +0 -134
- package/dist/chat/onboarding.persona.d.ts +0 -28
- package/dist/chat/onboarding.persona.js +0 -86
- package/dist/chat/onboarding.prompt.d.ts +0 -6
- package/dist/chat/onboarding.prompt.js +0 -63
- package/dist/chat/signal.persona.d.ts +0 -47
- package/dist/chat/signal.persona.js +0 -319
- package/dist/chat/signal.prompt.d.ts +0 -39
- package/dist/chat/signal.prompt.js +0 -136
- package/dist/contacts/contact.module.d.ts +0 -8
- package/dist/contacts/contact.module.js +0 -6
- package/dist/contacts/contact.repository.port.d.ts +0 -21
- package/dist/contacts/contact.repository.port.js +0 -12
- package/dist/contacts/contact.tools.d.ts +0 -17
- package/dist/contacts/contact.tools.js +0 -108
- package/dist/contacts/contact.tools.port.d.ts +0 -20
- package/dist/contacts/contact.tools.port.js +0 -16
- package/dist/contacts/contact.types.d.ts +0 -24
- package/dist/contacts/contact.types.js +0 -8
- package/dist/contexts/context.generator.d.ts +0 -95
- package/dist/contexts/context.generator.js +0 -127
- package/dist/contexts/context.module.d.ts +0 -13
- package/dist/contexts/context.module.js +0 -12
- package/dist/contexts/context.tools.port.d.ts +0 -9
- package/dist/discovery/hyde.documents.d.ts +0 -9
- package/dist/discovery/hyde.documents.js +0 -49
- package/dist/discovery/hyde.env.d.ts +0 -8
- package/dist/discovery/hyde.env.js +0 -9
- package/dist/discovery/hyde.frame.d.ts +0 -150
- package/dist/discovery/hyde.frame.js +0 -107
- package/dist/discovery/hyde.generator.d.ts +0 -38
- package/dist/discovery/hyde.generator.js +0 -103
- package/dist/discovery/hyde.graph.d.ts +0 -209
- package/dist/discovery/hyde.graph.js +0 -482
- package/dist/discovery/hyde.state.d.ts +0 -70
- package/dist/discovery/hyde.state.js +0 -85
- package/dist/discovery/hyde.strategies.d.ts +0 -17
- package/dist/discovery/hyde.strategies.js +0 -34
- package/dist/discovery/hyde.validator.d.ts +0 -78
- package/dist/discovery/hyde.validator.js +0 -48
- package/dist/discovery/index.d.ts +0 -26
- package/dist/discovery/index.js +0 -19
- package/dist/discovery/lens.inferrer.d.ts +0 -214
- package/dist/discovery/lens.inferrer.js +0 -152
- package/dist/enrichment/enrichment.generator.d.ts +0 -68
- package/dist/enrichment/enrichment.generator.js +0 -95
- package/dist/enrichment/enrichment.graph.d.ts +0 -544
- package/dist/enrichment/enrichment.graph.js +0 -695
- package/dist/enrichment/enrichment.state.d.ts +0 -141
- package/dist/enrichment/enrichment.state.js +0 -115
- package/dist/enrichment/enrichment.tools.context-read.d.ts +0 -10
- package/dist/enrichment/enrichment.tools.context-read.js +0 -353
- package/dist/enrichment/enrichment.tools.context-write.d.ts +0 -9
- package/dist/enrichment/enrichment.tools.context-write.js +0 -417
- package/dist/enrichment/enrichment.tools.d.ts +0 -13
- package/dist/enrichment/enrichment.tools.helpers.d.ts +0 -139
- package/dist/enrichment/enrichment.tools.helpers.js +0 -234
- package/dist/enrichment/enrichment.tools.js +0 -153
- package/dist/intents/graph/intent.graph.infer.d.ts +0 -44
- package/dist/intents/graph/intent.graph.infer.js +0 -97
- package/dist/intents/graph/intent.graph.js +0 -134
- package/dist/intents/graph/intent.graph.reconcile.js +0 -274
- package/dist/intents/graph/intent.graph.shared.d.ts +0 -68
- package/dist/intents/intake/intake.orchestrator.d.ts +0 -203
- package/dist/intents/intake/intake.orchestrator.js +0 -255
- package/dist/intents/intake/intake.pack.generator.d.ts +0 -57
- package/dist/intents/intake/intake.pack.generator.js +0 -90
- package/dist/intents/intent.clarifier.d.ts +0 -51
- package/dist/intents/intent.clarifier.js +0 -201
- package/dist/intents/intent.indexer.d.ts +0 -82
- package/dist/intents/intent.indexer.js +0 -170
- package/dist/intents/intent.module.js +0 -103
- package/dist/intents/intent.proposal.d.ts +0 -37
- package/dist/intents/intent.proposal.js +0 -14
- package/dist/intents/intent.reconciler.d.ts +0 -105
- package/dist/intents/intent.reconciler.js +0 -186
- package/dist/intents/intent.tools.d.ts +0 -27
- package/dist/intents/intent.tools.js +0 -808
- package/dist/maintenance/maintenance.graph.d.ts +0 -239
- package/dist/maintenance/maintenance.graph.js +0 -199
- package/dist/maintenance/maintenance.state.d.ts +0 -35
- package/dist/maintenance/maintenance.state.js +0 -55
- package/dist/mcp/elicitation.builder.d.ts +0 -53
- package/dist/mcp/elicitation.builder.js +0 -74
- package/dist/mcp/elicitation.dispatcher.d.ts +0 -36
- package/dist/mcp/elicitation.dispatcher.js +0 -86
- package/dist/mcp/mcp.authorization-policy.d.ts +0 -252
- package/dist/mcp/mcp.authorization-policy.js +0 -535
- package/dist/mcp/mcp.server.d.ts +0 -90
- package/dist/mcp/mcp.server.js +0 -631
- package/dist/negotiations/insight.generator.d.ts +0 -31
- package/dist/negotiations/insight.generator.js +0 -105
- package/dist/negotiations/negotiation.agent.d.ts +0 -130
- package/dist/negotiations/negotiation.agent.js +0 -396
- package/dist/negotiations/negotiation.answer-consumption.d.ts +0 -223
- package/dist/negotiations/negotiation.answer-consumption.js +0 -275
- package/dist/negotiations/negotiation.attribution.d.ts +0 -91
- package/dist/negotiations/negotiation.attribution.js +0 -109
- package/dist/negotiations/negotiation.candidates.d.ts +0 -83
- package/dist/negotiations/negotiation.candidates.js +0 -162
- package/dist/negotiations/negotiation.client-dm.d.ts +0 -50
- package/dist/negotiations/negotiation.client-dm.js +0 -66
- package/dist/negotiations/negotiation.consultation-policy.d.ts +0 -95
- package/dist/negotiations/negotiation.consultation-policy.js +0 -159
- package/dist/negotiations/negotiation.deadlock.contracts.d.ts +0 -10
- package/dist/negotiations/negotiation.deadlock.d.ts +0 -87
- package/dist/negotiations/negotiation.deadlock.js +0 -150
- package/dist/negotiations/negotiation.detail-reader.d.ts +0 -94
- package/dist/negotiations/negotiation.detail-reader.js +0 -91
- package/dist/negotiations/negotiation.expected-speaker.d.ts +0 -33
- package/dist/negotiations/negotiation.expected-speaker.js +0 -59
- package/dist/negotiations/negotiation.graph.d.ts +0 -694
- package/dist/negotiations/negotiation.graph.finalize.d.ts +0 -5
- package/dist/negotiations/negotiation.graph.finalize.js +0 -403
- package/dist/negotiations/negotiation.graph.init.d.ts +0 -54
- package/dist/negotiations/negotiation.graph.init.js +0 -256
- package/dist/negotiations/negotiation.graph.js +0 -94
- package/dist/negotiations/negotiation.graph.screen.d.ts +0 -23
- package/dist/negotiations/negotiation.graph.screen.js +0 -108
- package/dist/negotiations/negotiation.graph.shared.d.ts +0 -111
- package/dist/negotiations/negotiation.graph.shared.js +0 -168
- package/dist/negotiations/negotiation.graph.turn.d.ts +0 -134
- package/dist/negotiations/negotiation.graph.turn.js +0 -662
- package/dist/negotiations/negotiation.hermes-contract.d.ts +0 -31
- package/dist/negotiations/negotiation.hermes-contract.js +0 -72
- package/dist/negotiations/negotiation.intent-snapshot-provenance.d.ts +0 -21
- package/dist/negotiations/negotiation.intent-snapshot-provenance.js +0 -28
- package/dist/negotiations/negotiation.lifecycle-narration.d.ts +0 -18
- package/dist/negotiations/negotiation.lifecycle-narration.js +0 -87
- package/dist/negotiations/negotiation.memory.d.ts +0 -65
- package/dist/negotiations/negotiation.memory.js +0 -83
- package/dist/negotiations/negotiation.module.d.ts +0 -36
- package/dist/negotiations/negotiation.module.js +0 -23
- package/dist/negotiations/negotiation.protocol.d.ts +0 -1018
- package/dist/negotiations/negotiation.protocol.js +0 -224
- package/dist/negotiations/negotiation.question-safety.d.ts +0 -52
- package/dist/negotiations/negotiation.question-safety.js +0 -119
- package/dist/negotiations/negotiation.reflect.d.ts +0 -194
- package/dist/negotiations/negotiation.reflect.js +0 -145
- package/dist/negotiations/negotiation.scope.d.ts +0 -41
- package/dist/negotiations/negotiation.scope.js +0 -39
- package/dist/negotiations/negotiation.screen.contracts.d.ts +0 -88
- package/dist/negotiations/negotiation.screen.contracts.js +0 -58
- package/dist/negotiations/negotiation.screen.d.ts +0 -78
- package/dist/negotiations/negotiation.screen.js +0 -112
- package/dist/negotiations/negotiation.stall-gap.d.ts +0 -83
- package/dist/negotiations/negotiation.stall-gap.js +0 -152
- package/dist/negotiations/negotiation.stance.contracts.d.ts +0 -123
- package/dist/negotiations/negotiation.stance.contracts.js +0 -317
- package/dist/negotiations/negotiation.state.d.ts +0 -597
- package/dist/negotiations/negotiation.state.js +0 -286
- package/dist/negotiations/negotiation.summarizer.d.ts +0 -25
- package/dist/negotiations/negotiation.summarizer.js +0 -101
- package/dist/negotiations/negotiation.task-lock-policy.d.ts +0 -10
- package/dist/negotiations/negotiation.task-lock-policy.js +0 -22
- package/dist/negotiations/negotiation.tools.d.ts +0 -18
- package/dist/negotiations/negotiation.tools.js +0 -842
- package/dist/negotiations/negotiation.tools.port.d.ts +0 -17
- package/dist/negotiations/negotiation.turn-cap.d.ts +0 -9
- package/dist/negotiations/negotiation.turn-cap.js +0 -12
- package/dist/networks/indexer.state.js +0 -112
- package/dist/networks/network.tools.d.ts +0 -36
- package/dist/networks/network.tools.js +0 -594
- package/dist/opportunities/delivery-card.cache.d.ts +0 -25
- package/dist/opportunities/delivery-card.cache.js +0 -43
- package/dist/opportunities/discovery.env.d.ts +0 -20
- package/dist/opportunities/discovery.env.js +0 -109
- package/dist/opportunities/discriminator/discriminator.adjustments.d.ts +0 -90
- package/dist/opportunities/discriminator/discriminator.adjustments.js +0 -141
- package/dist/opportunities/discriminator/discriminator.assigner.d.ts +0 -78
- package/dist/opportunities/discriminator/discriminator.assigner.js +0 -153
- package/dist/opportunities/discriminator/discriminator.env.d.ts +0 -103
- package/dist/opportunities/discriminator/discriminator.env.js +0 -103
- package/dist/opportunities/discriminator/discriminator.miner.d.ts +0 -114
- package/dist/opportunities/discriminator/discriminator.miner.js +0 -228
- package/dist/opportunities/discriminator/discriminator.push.d.ts +0 -13
- package/dist/opportunities/discriminator/discriminator.push.js +0 -19
- package/dist/opportunities/discriminator/discriminator.question.d.ts +0 -58
- package/dist/opportunities/discriminator/discriminator.question.js +0 -155
- package/dist/opportunities/discriminator/discriminator.scorer.d.ts +0 -32
- package/dist/opportunities/discriminator/discriminator.scorer.js +0 -105
- package/dist/opportunities/discriminator/discriminator.shadow.d.ts +0 -32
- package/dist/opportunities/discriminator/discriminator.shadow.js +0 -90
- package/dist/opportunities/discriminator/discriminator.types.d.ts +0 -93
- package/dist/opportunities/discriminator/discriminator.types.js +0 -18
- package/dist/opportunities/negotiation-context.loader.d.ts +0 -59
- package/dist/opportunities/negotiation-context.loader.js +0 -90
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.env.d.ts +0 -43
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.env.js +0 -44
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.extractor.d.ts +0 -24
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.extractor.js +0 -188
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.miner.d.ts +0 -26
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.miner.js +0 -112
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.shadow.d.ts +0 -19
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.shadow.js +0 -61
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.types.d.ts +0 -191
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.types.js +0 -18
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.verifier.d.ts +0 -34
- package/dist/opportunities/negotiation-evidence/negotiation-evidence.verifier.js +0 -91
- package/dist/opportunities/negotiation-summary.builder.d.ts +0 -37
- package/dist/opportunities/negotiation-summary.builder.js +0 -66
- package/dist/opportunities/opportunity.discovery-negotiation-summary.d.ts +0 -14
- package/dist/opportunities/opportunity.discovery-negotiation-summary.js +0 -46
- package/dist/opportunities/opportunity.enricher.d.ts +0 -71
- package/dist/opportunities/opportunity.enricher.js +0 -280
- package/dist/opportunities/opportunity.evaluator.d.ts +0 -289
- package/dist/opportunities/opportunity.evaluator.js +0 -516
- package/dist/opportunities/opportunity.evidence.d.ts +0 -22
- package/dist/opportunities/opportunity.evidence.js +0 -87
- package/dist/opportunities/opportunity.existing-negotiation.d.ts +0 -79
- package/dist/opportunities/opportunity.existing-negotiation.js +0 -118
- package/dist/opportunities/opportunity.feed-selection.js +0 -96
- package/dist/opportunities/opportunity.graph.d.ts +0 -1611
- package/dist/opportunities/opportunity.graph.discovery-strategies.d.ts +0 -109
- package/dist/opportunities/opportunity.graph.discovery-strategies.js +0 -451
- package/dist/opportunities/opportunity.graph.discovery.d.ts +0 -69
- package/dist/opportunities/opportunity.graph.discovery.js +0 -397
- package/dist/opportunities/opportunity.graph.evaluation.d.ts +0 -82
- package/dist/opportunities/opportunity.graph.evaluation.js +0 -608
- package/dist/opportunities/opportunity.graph.js +0 -193
- package/dist/opportunities/opportunity.graph.modes.d.ts +0 -538
- package/dist/opportunities/opportunity.graph.modes.js +0 -538
- package/dist/opportunities/opportunity.graph.negotiate.d.ts +0 -109
- package/dist/opportunities/opportunity.graph.negotiate.js +0 -392
- package/dist/opportunities/opportunity.graph.persist-node.d.ts +0 -93
- package/dist/opportunities/opportunity.graph.persist-node.js +0 -765
- package/dist/opportunities/opportunity.graph.prep.d.ts +0 -150
- package/dist/opportunities/opportunity.graph.prep.js +0 -381
- package/dist/opportunities/opportunity.graph.shared.d.ts +0 -173
- package/dist/opportunities/opportunity.graph.shared.js +0 -199
- package/dist/opportunities/opportunity.introducer-feature.d.ts +0 -2
- package/dist/opportunities/opportunity.introducer-feature.js +0 -4
- package/dist/opportunities/opportunity.introducer.d.ts +0 -77
- package/dist/opportunities/opportunity.introducer.js +0 -99
- package/dist/opportunities/opportunity.labels.js +0 -10
- package/dist/opportunities/opportunity.lifecycle.d.ts +0 -63
- package/dist/opportunities/opportunity.lifecycle.js +0 -181
- package/dist/opportunities/opportunity.module.d.ts +0 -54
- package/dist/opportunities/opportunity.module.js +0 -39
- package/dist/opportunities/opportunity.newborn-stamping.d.ts +0 -41
- package/dist/opportunities/opportunity.newborn-stamping.js +0 -81
- package/dist/opportunities/opportunity.owner-approval.d.ts +0 -118
- package/dist/opportunities/opportunity.owner-approval.js +0 -34
- package/dist/opportunities/opportunity.owner-provenance.d.ts +0 -6
- package/dist/opportunities/opportunity.owner-provenance.js +0 -28
- package/dist/opportunities/opportunity.persist.d.ts +0 -58
- package/dist/opportunities/opportunity.persist.js +0 -145
- package/dist/opportunities/opportunity.persistence-admission.d.ts +0 -39
- package/dist/opportunities/opportunity.persistence-admission.js +0 -59
- package/dist/opportunities/opportunity.state.d.ts +0 -451
- package/dist/opportunities/opportunity.state.js +0 -256
- package/dist/opportunities/opportunity.tools.cards.d.ts +0 -138
- package/dist/opportunities/opportunity.tools.cards.js +0 -212
- package/dist/opportunities/opportunity.tools.d.ts +0 -12
- package/dist/opportunities/opportunity.tools.js +0 -236
- package/dist/opportunities/opportunity.tools.list.d.ts +0 -10
- package/dist/opportunities/opportunity.tools.list.js +0 -489
- package/dist/opportunities/opportunity.tools.port.d.ts +0 -16
- package/dist/opportunities/opportunity.utils.d.ts +0 -217
- package/dist/opportunities/opportunity.utils.js +0 -395
- package/dist/opportunities/outcome/outcome.env.d.ts +0 -60
- package/dist/opportunities/outcome/outcome.env.js +0 -63
- package/dist/opportunities/outcome/outcome.hypotheses.d.ts +0 -29
- package/dist/opportunities/outcome/outcome.hypotheses.js +0 -117
- package/dist/opportunities/outcome/outcome.shadow.d.ts +0 -56
- package/dist/opportunities/outcome/outcome.shadow.js +0 -87
- package/dist/opportunities/outcome/outcome.types.d.ts +0 -110
- package/dist/opportunities/outcome/outcome.types.js +0 -26
- package/dist/opportunities/radar/radar.health.d.ts +0 -31
- package/dist/opportunities/radar/radar.health.js +0 -75
- package/dist/premises/premise.analyzer.d.ts +0 -35
- package/dist/premises/premise.analyzer.js +0 -115
- package/dist/premises/premise.decomposer.d.ts +0 -69
- package/dist/premises/premise.decomposer.js +0 -213
- package/dist/premises/premise.graph.d.ts +0 -345
- package/dist/premises/premise.graph.js +0 -278
- package/dist/premises/premise.indexer.d.ts +0 -35
- package/dist/premises/premise.indexer.js +0 -86
- package/dist/premises/premise.state.d.ts +0 -67
- package/dist/premises/premise.state.js +0 -94
- package/dist/premises/premise.tools.d.ts +0 -3
- package/dist/premises/premise.tools.js +0 -248
- package/dist/questions/question.env.d.ts +0 -27
- package/dist/questions/question.env.js +0 -27
- package/dist/questions/question.input.d.ts +0 -107
- package/dist/questions/question.module.d.ts +0 -30
- package/dist/questions/question.module.js +0 -28
- package/dist/questions/question.schema.d.ts +0 -1529
- package/dist/questions/question.schema.js +0 -420
- package/dist/shared/agent/activity-projection.d.ts +0 -271
- package/dist/shared/agent/activity-projection.js +0 -254
- package/dist/shared/agent/canonical-guidance.d.ts +0 -30
- package/dist/shared/agent/canonical-guidance.js +0 -246
- package/dist/shared/agent/model.resolver.d.ts +0 -48
- package/dist/shared/agent/tool.factory.d.ts +0 -17
- package/dist/shared/agent/tool.factory.js +0 -221
- package/dist/shared/agent/tool.helpers.d.ts +0 -482
- package/dist/shared/agent/tool.helpers.js +0 -232
- package/dist/shared/agent/tool.registry.d.ts +0 -25
- package/dist/shared/agent/tool.registry.js +0 -76
- package/dist/shared/agent/tool.runtime.d.ts +0 -28
- package/dist/shared/agent/tool.runtime.js +0 -194
- package/dist/shared/agent/tool.scope.d.ts +0 -44
- package/dist/shared/agent/tool.scope.js +0 -50
- package/dist/shared/agent/utility.tools.d.ts +0 -15
- package/dist/shared/agent/utility.tools.js +0 -322
- package/dist/shared/assignment/network-assignment.policy.d.ts +0 -61
- package/dist/shared/assignment/network-assignment.policy.js +0 -105
- package/dist/shared/interfaces/agent-dispatcher.interface.d.ts +0 -100
- package/dist/shared/interfaces/agent-dispatcher.interface.js +0 -12
- package/dist/shared/interfaces/auth.interface.d.ts +0 -37
- package/dist/shared/interfaces/auth.interface.js +0 -1
- package/dist/shared/interfaces/chat-message-writer.interface.d.ts +0 -18
- package/dist/shared/interfaces/chat-message-writer.interface.js +0 -1
- package/dist/shared/interfaces/chat-session.interface.d.ts +0 -23
- package/dist/shared/interfaces/chat-session.interface.js +0 -18
- package/dist/shared/interfaces/chat-summary.interface.d.ts +0 -16
- package/dist/shared/interfaces/chat-summary.interface.js +0 -1
- package/dist/shared/interfaces/database.capabilities.d.ts +0 -100
- package/dist/shared/interfaces/database.interface.d.ts +0 -16
- package/dist/shared/interfaces/database.member-queries.d.ts +0 -219
- package/dist/shared/interfaces/database.member-queries.js +0 -4
- package/dist/shared/interfaces/database.negotiation.d.ts +0 -329
- package/dist/shared/interfaces/database.negotiation.js +0 -26
- package/dist/shared/interfaces/database.network-queries.js +0 -4
- package/dist/shared/interfaces/database.opportunity-queries.js +0 -4
- package/dist/shared/interfaces/delivery-ledger.interface.d.ts +0 -40
- package/dist/shared/interfaces/delivery-ledger.interface.js +0 -5
- package/dist/shared/interfaces/embedder.interface.d.ts +0 -92
- package/dist/shared/interfaces/embedder.interface.js +0 -4
- package/dist/shared/interfaces/enrichment-run.interface.d.ts +0 -62
- package/dist/shared/interfaces/enrichment-run.interface.js +0 -1
- package/dist/shared/interfaces/enrichment.interface.js +0 -1
- package/dist/shared/interfaces/negotiation-events.interface.d.ts +0 -77
- package/dist/shared/interfaces/negotiation-events.interface.js +0 -6
- package/dist/shared/interfaces/negotiation-summary.interface.d.ts +0 -25
- package/dist/shared/interfaces/negotiation-summary.interface.js +0 -1
- package/dist/shared/interfaces/negotiator-memory.interface.d.ts +0 -58
- package/dist/shared/interfaces/negotiator-memory.interface.js +0 -11
- package/dist/shared/interfaces/queue.interface.d.ts +0 -23
- package/dist/shared/interfaces/queue.interface.js +0 -4
- package/dist/shared/interfaces/scraper.interface.js +0 -1
- package/dist/shared/interfaces/tool-request-context.interface.d.ts +0 -11
- package/dist/shared/interfaces/tool-request-context.interface.js +0 -1
- package/dist/shared/observability/request-context.d.ts +0 -27
- package/dist/shared/observability/request-context.js +0 -6
- package/dist/shared/schemas/mcp-auth.schema.d.ts +0 -87
- package/dist/shared/schemas/mcp-auth.schema.js +0 -56
- package/dist/shared/schemas/negotiation-digest.schema.d.ts +0 -58
- package/dist/shared/schemas/negotiation-digest.schema.js +0 -38
- package/dist/shared/schemas/negotiation-state.schema.d.ts +0 -343
- package/dist/shared/schemas/negotiation-state.schema.js +0 -81
- package/dist/shared/schemas/question-block.fixture.d.ts +0 -12
- package/dist/shared/schemas/question-block.fixture.js +0 -39
- package/dist/shared/schemas/question-block.schema.d.ts +0 -111
- package/dist/shared/schemas/question-block.schema.js +0 -124
- package/dist/shared/schemas/structured-question.schema.d.ts +0 -66
- package/dist/shared/schemas/structured-question.schema.js +0 -31
- package/dist/shared/schemas/underspecification.schema.d.ts +0 -13
- package/dist/shared/schemas/underspecification.schema.js +0 -16
- /package/dist/{opportunities → internal/opportunities}/opportunity.update-admission.js +0 -0
- /package/dist/{opportunities → internal/opportunities}/radar/radar.state.js +0 -0
- /package/dist/{shared → internal/shared}/network/metadata.renderer.d.ts +0 -0
- /package/dist/{shared → internal/shared}/network/metadata.renderer.js +0 -0
- /package/dist/{shared → internal/shared}/observability/debug-meta.sanitizer.d.ts +0 -0
- /package/dist/{shared → internal/shared}/observability/debug-meta.sanitizer.js +0 -0
- /package/dist/{shared → internal/shared}/observability/performance.d.ts +0 -0
- /package/dist/{shared → internal/shared}/observability/performance.js +0 -0
- /package/dist/{shared → internal/shared}/observability/trace.d.ts +0 -0
- /package/dist/{shared → internal/shared}/observability/trace.js +0 -0
- /package/dist/{shared → internal/shared}/utils/claim-safety.d.ts +0 -0
- /package/dist/{shared → internal/shared}/utils/claim-safety.js +0 -0
- /package/dist/{shared → internal/shared}/utils/telegram-handle.d.ts +0 -0
- /package/dist/{shared → internal/shared}/utils/telegram-handle.js +0 -0
- /package/dist/{shared/interfaces/database.capabilities.js → platform/database/capabilities.js} +0 -0
- /package/dist/{shared/interfaces/database.entities.js → platform/database/entities.js} +0 -0
- /package/dist/{shared/interfaces/database.identity-queries.js → platform/database/identity-queries.js} +0 -0
- /package/dist/{agents/agent.dispatcher.port.js → platform/database/negotiation.js} +0 -0
- /package/dist/{chat/chat.persona.js → platform/database/opportunity-queries.js} +0 -0
- /package/dist/{contexts/context.tools.port.js → platform/discovery/embedder.js} +0 -0
- /package/dist/{shared/interfaces/scraper.interface.d.ts → platform/discovery/scraper.d.ts} +0 -0
- /package/dist/{negotiations/negotiation.deadlock.contracts.js → platform/discovery/scraper.js} +0 -0
- /package/dist/{shared/interfaces/enrichment.interface.d.ts → platform/enrichment/ports.d.ts} +0 -0
- /package/dist/{negotiations/negotiation.tools.port.js → platform/enrichment/ports.js} +0 -0
- /package/dist/{opportunities/opportunity.tools.port.js → platform/runtime/observability.js} +0 -0
- /package/dist/{questions/question.input.js → protocol/core.js} +0 -0
- /package/dist/{shared → protocol}/schemas/chat-context.schema.d.ts +0 -0
- /package/dist/{shared → protocol}/schemas/chat-context.schema.js +0 -0
|
@@ -33,9 +33,8 @@ import { createStructuredModel } from "../shared/agent/model.config.js";
|
|
|
33
33
|
* Generate presentation copy for an opportunity based on viewer context.
|
|
34
34
|
* Pure function — no side effects, no database access.
|
|
35
35
|
*/
|
|
36
|
-
export function presentOpportunity(opp, viewerId, otherPartyInfo,
|
|
36
|
+
export function presentOpportunity(opp, viewerId, otherPartyInfo, format) {
|
|
37
37
|
const myActor = opp.actors.find((a) => a.userId === viewerId);
|
|
38
|
-
const introducer = opp.actors.find((a) => a.role === 'introducer');
|
|
39
38
|
if (!myActor) {
|
|
40
39
|
throw new Error('Viewer is not an actor in this opportunity');
|
|
41
40
|
}
|
|
@@ -76,16 +75,9 @@ export function presentOpportunity(opp, viewerId, otherPartyInfo, introducerInfo
|
|
|
76
75
|
break;
|
|
77
76
|
case 'party':
|
|
78
77
|
default:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
descriptionIsReasoning = true;
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
title = `Opportunity with ${otherName}`;
|
|
86
|
-
description = safeReasoning;
|
|
87
|
-
descriptionIsReasoning = true;
|
|
88
|
-
}
|
|
78
|
+
title = `Opportunity with ${otherName}`;
|
|
79
|
+
description = safeReasoning;
|
|
80
|
+
descriptionIsReasoning = true;
|
|
89
81
|
break;
|
|
90
82
|
}
|
|
91
83
|
if (!descriptionIsReasoning) {
|
|
@@ -147,67 +139,6 @@ export function truncateAtBoundary(text, maxChars) {
|
|
|
147
139
|
const body = lastSpace > 0 ? slice.slice(0, lastSpace) : slice;
|
|
148
140
|
return body.replace(/[\s,;:.!?'"-]+$/, "").trim() + "\u2026";
|
|
149
141
|
}
|
|
150
|
-
/**
|
|
151
|
-
* Strips introducer mentions from opportunity summary text.
|
|
152
|
-
* Removes patterns like:
|
|
153
|
-
* - "[Introducer] introduced you to [Counterpart]"
|
|
154
|
-
* - "[Introducer] thinks you should meet [Counterpart]"
|
|
155
|
-
* - "[Introducer] connected you to [Counterpart]"
|
|
156
|
-
* - "[Introducer] suggested you meet [Counterpart]"
|
|
157
|
-
*
|
|
158
|
-
* @param text - The text to clean (personalizedSummary)
|
|
159
|
-
* @param introducerName - Full name of the introducer to strip
|
|
160
|
-
* @returns Text with introducer mentions removed, counterpart preserved
|
|
161
|
-
*/
|
|
162
|
-
export function stripIntroducerMentions(text, introducerName) {
|
|
163
|
-
if (!introducerName?.trim())
|
|
164
|
-
return text;
|
|
165
|
-
const fullName = introducerName.trim();
|
|
166
|
-
const firstName = fullName.split(/\s+/)[0];
|
|
167
|
-
const namesToCheck = [fullName];
|
|
168
|
-
if (firstName && firstName.length > 1) {
|
|
169
|
-
namesToCheck.push(firstName);
|
|
170
|
-
}
|
|
171
|
-
let result = text;
|
|
172
|
-
for (const [idx, name] of namesToCheck.entries()) {
|
|
173
|
-
const escapedName = escapeRegex(name);
|
|
174
|
-
// Pattern: "Name introduced you to " (with or without comma, optionally with "directly")
|
|
175
|
-
result = result.replace(new RegExp(`\\b${escapedName}\\s+introduced\\s+you\\s+(?:directly\\s+)?to\\s*`, "gi"), "");
|
|
176
|
-
// Pattern: "Name thinks you should meet "
|
|
177
|
-
result = result.replace(new RegExp(`\\b${escapedName}\\s+thinks\\s+you\\s+should\\s+meet\\s*`, "gi"), "");
|
|
178
|
-
// Pattern: "Name connected you to "
|
|
179
|
-
result = result.replace(new RegExp(`\\b${escapedName}\\s+connected\\s+you\\s+(?:to|with)\\s*`, "gi"), "");
|
|
180
|
-
// Pattern: "Name suggested you meet "
|
|
181
|
-
result = result.replace(new RegExp(`\\b${escapedName}\\s+suggested\\s+you\\s+(?:meet|connect\\s+(?:to|with))\\s*`, "gi"), "");
|
|
182
|
-
// Pattern: "Name recommended you meet "
|
|
183
|
-
result = result.replace(new RegExp(`\\b${escapedName}\\s+recommended\\s+you\\s+(?:meet|connect)\\s*`, "gi"), "");
|
|
184
|
-
// Pattern: "Name thinks you and Counterpart should meet" -> remove entire phrase up to Counterpart
|
|
185
|
-
result = result.replace(new RegExp(`\\b${escapedName}\\s+thinks\\s+you\\s+and\\s+`, "gi"), "");
|
|
186
|
-
// Pattern: "Name also thought..." - remove sentences starting with Name + also/also thought
|
|
187
|
-
result = result.replace(new RegExp(`\\b${escapedName}\\s+(?:also\\s+)?(?:thought|thinks?|believes?|felt)\\s*`, "gi"), "");
|
|
188
|
-
// General: Remove any remaining standalone mention of the introducer name at sentence start.
|
|
189
|
-
// Only apply for fullName (idx === 0) to avoid stripping valid counterpart first names
|
|
190
|
-
// (e.g. "David Smith" intro to "David Johnson" → we strip "David Smith" but not "David" in "David Johnson").
|
|
191
|
-
if (idx === 0) {
|
|
192
|
-
result = result.replace(new RegExp(`(?:^|\\.\\s*)\\b${escapedName}\\s+`, "gi"), (match, offset) => {
|
|
193
|
-
if (offset === 0 || match.startsWith(".")) {
|
|
194
|
-
return match.startsWith(".") ? ". " : "";
|
|
195
|
-
}
|
|
196
|
-
return match;
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
// Clean up: remove leading/trailing whitespace and common punctuation artifacts
|
|
201
|
-
result = result
|
|
202
|
-
.replace(/^[\,\s]+/, "") // Remove leading commas/spaces
|
|
203
|
-
.replace(/\s{2,}/g, " ") // Normalize multiple spaces
|
|
204
|
-
.trim();
|
|
205
|
-
// Capitalize first letter if we removed from start
|
|
206
|
-
if (result.length > 0) {
|
|
207
|
-
result = result.charAt(0).toUpperCase() + result.slice(1);
|
|
208
|
-
}
|
|
209
|
-
return result;
|
|
210
|
-
}
|
|
211
142
|
// Helper function
|
|
212
143
|
function escapeRegex(s) {
|
|
213
144
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -240,20 +171,15 @@ function splitSentences(text) {
|
|
|
240
171
|
* @param counterpartName - Display name of the suggested connection (e.g. "Alex Chen").
|
|
241
172
|
* @param maxChars - Max length of returned string (default MINIMAL_MAIN_TEXT_MAX_CHARS).
|
|
242
173
|
* @param viewerName - Optional display name of the viewer (signed-in user). When provided, sentences or prefixes describing the viewer are skipped so the card introduces the counterpart, not the viewer.
|
|
243
|
-
* @param introducerName - Optional display name of the introducer. When provided, introducer phrases (e.g., "X introduced you to...") are stripped from the summary to keep the body text focused on match quality.
|
|
244
174
|
* @returns Viewer-centric snippet mentioning the counterpart when possible; if counterpartName is empty, returns reasoning truncated to maxChars. Never null; may be "A suggested connection." when reasoning is empty.
|
|
245
175
|
*/
|
|
246
|
-
export function viewerCentricCardSummary(reasoning, counterpartName, maxChars = MINIMAL_MAIN_TEXT_MAX_CHARS, viewerName
|
|
176
|
+
export function viewerCentricCardSummary(reasoning, counterpartName, maxChars = MINIMAL_MAIN_TEXT_MAX_CHARS, viewerName) {
|
|
247
177
|
const raw = stripUnsupportedOpportunityClaims(stripUuids(reasoning));
|
|
248
178
|
if (!raw)
|
|
249
179
|
return "A suggested connection.";
|
|
250
180
|
const name = counterpartName.trim();
|
|
251
181
|
if (!name) {
|
|
252
182
|
let out = raw.length <= maxChars ? raw : raw.slice(0, maxChars) + "...";
|
|
253
|
-
// Strip introducer mentions BEFORE replacing viewer name to avoid "you introduced..." artifacts
|
|
254
|
-
if (introducerName) {
|
|
255
|
-
out = stripIntroducerMentions(out, introducerName);
|
|
256
|
-
}
|
|
257
183
|
out = replaceViewerNameWithYou(out, viewerName);
|
|
258
184
|
return out;
|
|
259
185
|
}
|
|
@@ -279,10 +205,6 @@ export function viewerCentricCardSummary(reasoning, counterpartName, maxChars =
|
|
|
279
205
|
if (cleanIdx !== -1) {
|
|
280
206
|
const result = sentences.slice(cleanIdx).join(" ").trim();
|
|
281
207
|
let out = result.length <= maxChars ? result : result.slice(0, maxChars) + "...";
|
|
282
|
-
// Strip introducer mentions BEFORE replacing viewer name to avoid "you introduced..." artifacts
|
|
283
|
-
if (introducerName) {
|
|
284
|
-
out = stripIntroducerMentions(out, introducerName);
|
|
285
|
-
}
|
|
286
208
|
out = replaceViewerNameWithYou(out, viewerName, [name]);
|
|
287
209
|
return out;
|
|
288
210
|
}
|
|
@@ -301,10 +223,6 @@ export function viewerCentricCardSummary(reasoning, counterpartName, maxChars =
|
|
|
301
223
|
const rest = sentences.slice(compoundIdx + 1).join(" ").trim();
|
|
302
224
|
const result = rest ? `${extracted} ${rest}` : extracted;
|
|
303
225
|
let out = result.length <= maxChars ? result : result.slice(0, maxChars) + "...";
|
|
304
|
-
// Strip introducer mentions BEFORE replacing viewer name to avoid "you introduced..." artifacts
|
|
305
|
-
if (introducerName) {
|
|
306
|
-
out = stripIntroducerMentions(out, introducerName);
|
|
307
|
-
}
|
|
308
226
|
out = replaceViewerNameWithYou(out, viewerName, [name]);
|
|
309
227
|
return out;
|
|
310
228
|
}
|
|
@@ -314,10 +232,6 @@ export function viewerCentricCardSummary(reasoning, counterpartName, maxChars =
|
|
|
314
232
|
const idx = sentences.findIndex(hasCounterpartName);
|
|
315
233
|
if (idx === -1) {
|
|
316
234
|
let out = raw.length <= maxChars ? raw : raw.slice(0, maxChars) + "...";
|
|
317
|
-
// Strip introducer mentions BEFORE replacing viewer name to avoid "you introduced..." artifacts
|
|
318
|
-
if (introducerName) {
|
|
319
|
-
out = stripIntroducerMentions(out, introducerName);
|
|
320
|
-
}
|
|
321
235
|
out = replaceViewerNameWithYou(out, viewerName, [name]);
|
|
322
236
|
return out;
|
|
323
237
|
}
|
|
@@ -325,10 +239,6 @@ export function viewerCentricCardSummary(reasoning, counterpartName, maxChars =
|
|
|
325
239
|
let out = fromCounterpart.length <= maxChars
|
|
326
240
|
? fromCounterpart
|
|
327
241
|
: fromCounterpart.slice(0, maxChars) + "...";
|
|
328
|
-
// Strip introducer mentions BEFORE replacing viewer name to avoid "you introduced..." artifacts
|
|
329
|
-
if (introducerName) {
|
|
330
|
-
out = stripIntroducerMentions(out, introducerName);
|
|
331
|
-
}
|
|
332
242
|
out = replaceViewerNameWithYou(out, viewerName, [name]);
|
|
333
243
|
return out;
|
|
334
244
|
}
|
|
@@ -344,9 +254,7 @@ const FALLBACK_REMARK = "A potential connection worth exploring.";
|
|
|
344
254
|
* reasoning and frames them in a short template like "Shared interest in AI and design."
|
|
345
255
|
*
|
|
346
256
|
* This is a regex-based heuristic — an alternative is OpportunityPresenter.presentCard()
|
|
347
|
-
* which generates narratorRemark via LLM with much higher quality
|
|
348
|
-
* home.graph.ts and opportunity.discover.ts). See buildMinimalOpportunityCard() in
|
|
349
|
-
* opportunity.tools.ts for the trade-off discussion.
|
|
257
|
+
* which generates narratorRemark via LLM with much higher quality.
|
|
350
258
|
*
|
|
351
259
|
* @param reasoning - Raw interpretation.reasoning text.
|
|
352
260
|
* @param counterpartName - Display name of the counterpart (stripped from output).
|
|
@@ -544,11 +452,9 @@ function replaceViewerNameWithYou(text, viewerName, otherNames) {
|
|
|
544
452
|
// ──────────────────────────────────────────────────────────────────────
|
|
545
453
|
/** Cache namespace for opportunity presentation copy. Bump to invalidate copy safety changes. */
|
|
546
454
|
export const OPPORTUNITY_PRESENTATION_CACHE_VERSION = "v2";
|
|
547
|
-
export function buildRadarCardPresentationCacheKey(opportunityId, status, viewerId) {
|
|
548
|
-
|
|
549
|
-
}
|
|
550
|
-
export function buildDeliveryCardPresentationCacheKey(opportunityId, status, viewerId) {
|
|
551
|
-
return `delivery:${OPPORTUNITY_PRESENTATION_CACHE_VERSION}:card:${opportunityId}:${status}:${viewerId}`;
|
|
455
|
+
export function buildRadarCardPresentationCacheKey(opportunityId, status, viewerId, focusedViewerIntentId) {
|
|
456
|
+
const scope = focusedViewerIntentId ? `:intent:${focusedViewerIntentId}` : "";
|
|
457
|
+
return `radar:${OPPORTUNITY_PRESENTATION_CACHE_VERSION}:card:${opportunityId}:${status}:${viewerId}${scope}`;
|
|
552
458
|
}
|
|
553
459
|
export function buildApiChatCardPresentationCacheKey(opportunityId, viewerId) {
|
|
554
460
|
return `chat:${OPPORTUNITY_PRESENTATION_CACHE_VERSION}:card:${opportunityId}:${viewerId}`;
|
|
@@ -567,7 +473,7 @@ export function buildApiChatCardPresentationCacheKey(opportunityId, viewerId) {
|
|
|
567
473
|
*
|
|
568
474
|
* raw reasoning
|
|
569
475
|
* → whitespace-normalize
|
|
570
|
-
* → viewer-centric rewrite (incl. UUID stripping
|
|
476
|
+
* → viewer-centric rewrite (incl. UUID stripping)
|
|
571
477
|
* → boundary-aware truncation
|
|
572
478
|
* → per-surface empty-text default
|
|
573
479
|
*
|
|
@@ -588,7 +494,7 @@ export const DEFAULT_FALLBACK_ACTION = "Take a look and decide whether to reach
|
|
|
588
494
|
/**
|
|
589
495
|
* Produce safe user-facing fallback copy from raw match reasoning.
|
|
590
496
|
*
|
|
591
|
-
* This is the ONE sanitization standard: UUID stripping,
|
|
497
|
+
* This is the ONE sanitization standard: UUID stripping,
|
|
592
498
|
* stripping, and viewer-centric rewrite (via {@link viewerCentricCardSummary}),
|
|
593
499
|
* followed by whitespace normalization and boundary-aware truncation (via
|
|
594
500
|
* {@link truncateAtBoundary}). Never returns raw reasoning verbatim beyond
|
|
@@ -606,10 +512,10 @@ export function safeFallbackSummary(rawReasoning, opts = {}) {
|
|
|
606
512
|
const claimSafeInput = stripUnsupportedOpportunityClaims(normalized);
|
|
607
513
|
if (!claimSafeInput)
|
|
608
514
|
return emptyText;
|
|
609
|
-
// viewerCentricCardSummary handles UUID stripping,
|
|
515
|
+
// viewerCentricCardSummary handles UUID stripping,
|
|
610
516
|
// stripping, and the viewer-centric rewrite. Pass Infinity so truncation is
|
|
611
517
|
// handled by boundary-aware logic below instead of a mid-word hard slice.
|
|
612
|
-
const rewritten = viewerCentricCardSummary(claimSafeInput, opts.counterpartName ?? "", Number.POSITIVE_INFINITY, opts.viewerName
|
|
518
|
+
const rewritten = viewerCentricCardSummary(claimSafeInput, opts.counterpartName ?? "", Number.POSITIVE_INFINITY, opts.viewerName);
|
|
613
519
|
// Claim validation intentionally runs after viewer-centric rewriting: rewrite
|
|
614
520
|
// heuristics may select or join different source sentences, and the final
|
|
615
521
|
// user-facing sentence set is what must be safe.
|
|
@@ -684,10 +590,6 @@ export const CardLLMSchema = z.object({
|
|
|
684
590
|
personalizedSummary: z
|
|
685
591
|
.string()
|
|
686
592
|
.describe("2-3 sentence explanation in 'you' language for the main card body"),
|
|
687
|
-
digestSummary: z
|
|
688
|
-
.string()
|
|
689
|
-
.max(220)
|
|
690
|
-
.describe("One concise digest-ready sentence for a morning brief. It must be addressed to the viewer and mention the counterpart by name, e.g. 'You might like meeting Paul because ...'. No markdown."),
|
|
691
593
|
suggestedAction: z
|
|
692
594
|
.string()
|
|
693
595
|
.describe("Brief suggested next step (e.g. CTA line)"),
|
|
@@ -721,20 +623,9 @@ Rules:
|
|
|
721
623
|
6. Prefer first names in user-facing copy. Do not repeatedly use full names unless needed to disambiguate.
|
|
722
624
|
7. Network assignment, network title/type, and network/event metadata are retrieval context only. They are NEVER proof that a person attended or will attend, belongs to a group, resides in a place, knows anyone from the network, or shared a session, time, place, or location with anyone. Do not make co-attendance, membership, residence, shared-session, or same-place/same-time claims from network co-membership.
|
|
723
625
|
|
|
724
|
-
**Introduction-originated opportunities:**
|
|
725
|
-
When INTRODUCTION CONTEXT is provided, this opportunity was explicitly created by an introducer (a real person who saw value in this connection). This is NOT an automatic system discovery — someone made a deliberate judgment.
|
|
726
|
-
- For ALL roles: acknowledge the introducer's role naturally. E.g., "[Introducer name] thinks you should meet [other person]" or "[Introducer name] connected you because..."
|
|
727
|
-
- The introduction itself is a strong signal — treat it with the weight of a personal recommendation.
|
|
728
|
-
- If the parties' intents don't obviously overlap, that's fine — the introducer saw something worth connecting. Focus on what the introducer likely saw.
|
|
729
626
|
|
|
730
627
|
**Role-Specific Presentation:**
|
|
731
628
|
|
|
732
|
-
**If viewer is "introducer":**
|
|
733
|
-
- The viewer suggested this connection between two (or more) OTHER people. The opportunity is NOT about the viewer's own needs.
|
|
734
|
-
- Headline: describe the connection between the parties (e.g., "Connecting a React expert with a startup founder").
|
|
735
|
-
- Personalized summary: explain why the people YOU are introducing should meet. Reference THEIR profiles and intents, not yours. Frame it as "you're connecting X and Y because..." rather than "this matches your intent".
|
|
736
|
-
- Suggested action: guide sharing (e.g., "Share this with [name] to get things started").
|
|
737
|
-
- CRITICAL: Do NOT reference the introducer's own intents, skills, or needs. The introducer is the matchmaker, not a party.
|
|
738
629
|
|
|
739
630
|
**If viewer is "patient" or "party":**
|
|
740
631
|
- Reference their specific intents, skills, or interests that align with this opportunity.
|
|
@@ -764,10 +655,9 @@ You are an expert at presenting connection opportunities for an opportunity card
|
|
|
764
655
|
Given context about the viewer, the other person, and why they were matched, produce:
|
|
765
656
|
1. headline: one short hook line.
|
|
766
657
|
2. personalizedSummary: 2-3 sentences in "you" language (main body text).
|
|
767
|
-
3.
|
|
768
|
-
4.
|
|
769
|
-
5.
|
|
770
|
-
6. greeting: a 2-4 sentence first-person message the viewer could send to the counterpart. Plain prose, no greeting prefix, no markdown.
|
|
658
|
+
3. suggestedAction: one brief suggested next step.
|
|
659
|
+
4. narratorRemark: one short sentence for the narrator chip (who is suggesting and why; max ~80 chars).
|
|
660
|
+
5. greeting: a 2-4 sentence first-person message the viewer could send to the counterpart. Plain prose, no greeting prefix, no markdown.
|
|
771
661
|
7. mutualIntentsLabel: short subtitle under the other party's name. Examples: "3 mutual intents", "Shared interests", "Aligned goals" — keep it brief. NEVER output "0 mutual intents" or any zero-count label; use a qualitative phrase instead.
|
|
772
662
|
|
|
773
663
|
Rules:
|
|
@@ -777,56 +667,15 @@ Rules:
|
|
|
777
667
|
- Vary wording for the match itself. Do not repeat "opportunity" across headline, summary, and narratorRemark when alternatives fit.
|
|
778
668
|
- Prefer first names in user-facing copy. Avoid repeated full names unless disambiguation is necessary.
|
|
779
669
|
- Network assignment, network title/type, and network/event metadata are retrieval context only. They are NEVER proof that a person attended or will attend, belongs to a group, resides in a place, knows anyone from the network, or shared a session, time, place, or location with anyone. Do not make co-attendance, membership, residence, shared-session, or same-place/same-time claims from network co-membership.
|
|
780
|
-
- digestSummary must be grammatically complete as a standalone sentence. It should usually start with "You might like meeting {Name} because ..." for direct connections, or "You may be able to help {Name} because ..." for connector/introducer cards.
|
|
781
|
-
- digestSummary must NOT use awkward third-person fragments like "Name is...", "they're ..., and is...", "you is...", or "the discoverer's query".
|
|
782
|
-
- digestSummary must be one sentence, MUST fit within 180 characters when possible, and MUST contain no markdown links; the caller will attach links.
|
|
783
670
|
- If you cannot fit every detail, choose one clear reason and stop. Do not rely on downstream truncation.
|
|
784
671
|
|
|
785
|
-
**Introduction-originated opportunities (ONLY when INTRODUCTION CONTEXT is provided):**
|
|
786
|
-
When INTRODUCTION CONTEXT is provided, this opportunity was explicitly created by an introducer. It was NOT automatically discovered.
|
|
787
|
-
- For parties/patients/agents/peers viewing an introduction: keep the introducer signal in narratorRemark (and narrator chip), not in personalizedSummary.
|
|
788
|
-
- For these introduced parties, personalizedSummary must focus ONLY on fit/value between viewer and counterpart. Do NOT mention the introducer there.
|
|
789
|
-
- narratorRemark should carry the introduction signal (e.g., "saw strong alignment between you two" or "thought this connection could be valuable"), without repeating the narrator name at the start.
|
|
790
|
-
- This is a personal recommendation, not an algorithm match. Frame it accordingly.
|
|
791
|
-
|
|
792
|
-
**CRITICAL: NEVER include introducer names in personalizedSummary. Examples:**
|
|
793
|
-
❌ WRONG: "Seref introduced you to Lucy, who is actively seeking a product co-founder..."
|
|
794
|
-
✅ CORRECT: "Lucy is actively seeking a product co-founder for a niche APAC marketplace. With your expertise in UX and AI, this could be an ideal collaboration."
|
|
795
|
-
|
|
796
|
-
❌ WRONG: "Bob thinks you should meet Alice because your React skills align with her needs."
|
|
797
|
-
✅ CORRECT: "Alice is building a React-based platform and needs frontend expertise. Your experience with component architecture makes you a strong fit."
|
|
798
|
-
|
|
799
|
-
❌ WRONG: "Jane connected you to Mark, who is looking for a designer."
|
|
800
|
-
✅ CORRECT: "Mark is building a consumer app and needs design expertise. Your background in user-centered design aligns well with what he's building."
|
|
801
|
-
|
|
802
|
-
Remember: The introducer's name goes ONLY in narratorRemark, NEVER in personalizedSummary.
|
|
803
|
-
|
|
804
|
-
**When INTRODUCTION CONTEXT is NOT provided (system-discovered match):**
|
|
805
|
-
- Do NOT use introducer-style wording. Do NOT say "you suggested", "this is an introduction you suggested", or "you suggested this connection". The system found this match; no human introducer was involved.
|
|
806
|
-
- Instead, narratorRemark should describe why the match is relevant (e.g. "Based on your overlapping intents", "Your skills align with what they need").
|
|
807
|
-
|
|
808
672
|
**Negotiation-grounded explanations (ONLY when NEGOTIATION CONTEXT is provided):**
|
|
809
673
|
When NEGOTIATION CONTEXT is provided, this opportunity passed through an agent-to-agent negotiation. Use the transcript to ground your explanation in the concrete reasoning the agents exchanged.
|
|
810
674
|
- Personalize the summary with *why* the negotiation produced this match — reference the roles the agents agreed on, the specific concerns raised, and how they were resolved.
|
|
811
|
-
- For status "stalled" with reason "turn_cap": the agents hit the turn limit without reaching agreement. Frame the card as a hedged possibility rather than a confident match; narratorRemark should signal "agents couldn't fully converge" without sounding negative.
|
|
812
|
-
- For status "stalled" with reason "timeout": one side went silent. Suggest the user re-engage if interested.
|
|
813
675
|
- For status "accepted": the agents agreed; the card should confidently explain *why* they agreed.
|
|
814
676
|
- For status "rejected": the agents declined. The card should explain the reason briefly so the user understands — not dwell on it.
|
|
815
677
|
- Do NOT invent turn content. Only reference what is in the NEGOTIATION CONTEXT block.
|
|
816
678
|
|
|
817
|
-
- Exception for connector/introducer: if viewer role is "introducer" (any status), this is a curation/connector card. Use:
|
|
818
|
-
- suggestedAction: one short line about sharing the intro or confirming the match.
|
|
819
|
-
- mutualIntentsLabel: a short connector label (e.g. "Connector match", "You can bridge this").
|
|
820
|
-
- headline: describe the connection between the parties (e.g., "Connecting a PhD researcher with a translator"). Do NOT reference the introducer's own needs.
|
|
821
|
-
- personalizedSummary: explain why the parties you're introducing should meet, referencing THEIR profiles and intents, not yours.
|
|
822
|
-
|
|
823
|
-
**CRITICAL for latent introducer cards (opportunity status is "latent"):**
|
|
824
|
-
When the viewer is the introducer and the opportunity status is "latent", the introducer has NOT yet approved this match. They are evaluating whether to make the introduction.
|
|
825
|
-
- narratorRemark MUST use evaluation/curation language (e.g. "Could be a strong match", "Worth introducing?", "Interesting overlap here").
|
|
826
|
-
- Do NOT say "you suggested", "you introduced", "you connected", or any past-tense language implying the introduction was already made.
|
|
827
|
-
- suggestedAction should encourage evaluation (e.g. "Approve if you see the fit").
|
|
828
|
-
- Exception for new-connection reveal: if viewer role is "agent", status is "accepted", and there is an introducer, this is the agent's first time seeing this opportunity. Use:
|
|
829
|
-
- suggestedAction: a short line about joining the conversation.
|
|
830
679
|
`;
|
|
831
680
|
// ──────────────────────────────────────────────────────────────
|
|
832
681
|
// DETERMINISTIC OUTPUT VALIDATION
|
|
@@ -875,9 +724,6 @@ export class OpportunityPresenter {
|
|
|
875
724
|
* Generate personalized presentation for a single opportunity.
|
|
876
725
|
*/
|
|
877
726
|
async present(input, options = {}) {
|
|
878
|
-
const introContext = input.isIntroduction
|
|
879
|
-
? `\nINTRODUCTION CONTEXT: This opportunity was created by an explicit introduction from ${input.introducerName ?? "someone in the community"}. It was NOT discovered automatically — a real person made this connection.\n`
|
|
880
|
-
: "";
|
|
881
727
|
const humanContent = `
|
|
882
728
|
VIEWER (the person seeing this opportunity):
|
|
883
729
|
${input.viewerContext}
|
|
@@ -890,8 +736,7 @@ MATCH CONTEXT:
|
|
|
890
736
|
- Confidence: ${input.confidence}
|
|
891
737
|
- Why we matched: ${input.matchReasoning}
|
|
892
738
|
- Signals: ${input.signalsSummary}
|
|
893
|
-
${
|
|
894
|
-
COMMUNITY: ${input.indexName}
|
|
739
|
+
COMMUNITY: ${input.networkName}
|
|
895
740
|
Viewer's role in this opportunity: ${input.viewerRole}
|
|
896
741
|
|
|
897
742
|
Produce headline, personalizedSummary (2-3 sentences in "you" language), suggestedAction, and greeting.
|
|
@@ -953,15 +798,12 @@ Produce headline, personalizedSummary (2-3 sentences in "you" language), suggest
|
|
|
953
798
|
const mutualHint = input.mutualIntentCount != null && input.mutualIntentCount > 0
|
|
954
799
|
? `There are ${input.mutualIntentCount} overlapping intent(s) between viewer and other party.`
|
|
955
800
|
: "Match is based on profile and intent alignment. Do not cite a numeric intent count.";
|
|
956
|
-
const introContext = input.isIntroduction
|
|
957
|
-
? `\nINTRODUCTION CONTEXT: This opportunity was created by an explicit introduction from ${input.introducerName ?? "someone in the community"}. It was NOT discovered automatically — a real person made this connection.\n`
|
|
958
|
-
: "";
|
|
959
801
|
const negotiationBlock = buildNegotiationPromptBlock(input.negotiationContext);
|
|
960
802
|
// When negotiation context exists, lead with it — these cards exist
|
|
961
803
|
// *because* the negotiation happened. Trailing the block lets weaker
|
|
962
804
|
// models lean on surface signals and ignore the transcript entirely.
|
|
963
805
|
const negotiationDirective = negotiationBlock
|
|
964
|
-
? `\nIMPORTANT: This opportunity surfaced because the agents negotiated and converged.
|
|
806
|
+
? `\nIMPORTANT: This opportunity surfaced because the agents negotiated and converged. Your personalizedSummary MUST reference at least one specific signal from the NEGOTIATION CONTEXT block below — what concern was raised, what was confirmed, what the agents agreed on. It must communicate *why this specific match* surfaced now (the negotiation that led to it), not a generic skill-complementarity line. Do not produce the generic summary every card looked like before this negotiation happened.\n`
|
|
965
807
|
: "";
|
|
966
808
|
const humanContent = `
|
|
967
809
|
${negotiationBlock}${negotiationDirective}
|
|
@@ -977,14 +819,12 @@ MATCH CONTEXT:
|
|
|
977
819
|
- Why we matched: ${input.matchReasoning}
|
|
978
820
|
- Signals: ${input.signalsSummary}
|
|
979
821
|
- ${mutualHint}
|
|
980
|
-
${
|
|
981
|
-
COMMUNITY: ${input.indexName}
|
|
822
|
+
COMMUNITY: ${input.networkName}
|
|
982
823
|
Viewer's role in this opportunity: ${input.viewerRole}
|
|
983
824
|
Opportunity status: ${input.opportunityStatus ?? "pending"}
|
|
984
825
|
|
|
985
|
-
Produce headline, personalizedSummary,
|
|
826
|
+
Produce headline, personalizedSummary, suggestedAction, narratorRemark, greeting, and mutualIntentsLabel.
|
|
986
827
|
`;
|
|
987
|
-
const isIntroducer = input.viewerRole === "introducer";
|
|
988
828
|
try {
|
|
989
829
|
const messages = [
|
|
990
830
|
new SystemMessage(homeCardSystemPrompt),
|
|
@@ -995,26 +835,18 @@ Produce headline, personalizedSummary, digestSummary, suggestedAction, narratorR
|
|
|
995
835
|
if (/^0\s+(mutual|overlapping)\s+intent/i.test(parsed.presentation.mutualIntentsLabel)) {
|
|
996
836
|
parsed.presentation.mutualIntentsLabel = "Shared interests";
|
|
997
837
|
}
|
|
998
|
-
if (input.isIntroduction && input.introducerName) {
|
|
999
|
-
parsed.presentation.personalizedSummary = stripIntroducerMentions(parsed.presentation.personalizedSummary, input.introducerName);
|
|
1000
|
-
parsed.presentation.digestSummary = stripIntroducerMentions(parsed.presentation.digestSummary, input.introducerName);
|
|
1001
|
-
}
|
|
1002
838
|
const fields = {
|
|
1003
839
|
headline: sanitizePresenterField(parsed.presentation.headline, DEFAULT_FALLBACK_HEADLINE),
|
|
1004
840
|
personalizedSummary: sanitizePresenterField(parsed.presentation.personalizedSummary, DEFAULT_EMPTY_FALLBACK_TEXT),
|
|
1005
|
-
digestSummary: sanitizePresenterField(parsed.presentation.digestSummary, isIntroducer
|
|
1006
|
-
? "You may be able to help make a useful introduction here."
|
|
1007
|
-
: "You might like meeting them based on your current interests."),
|
|
1008
841
|
suggestedAction: sanitizePresenterField(parsed.presentation.suggestedAction, DEFAULT_FALLBACK_ACTION),
|
|
1009
842
|
narratorRemark: sanitizePresenterField(parsed.presentation.narratorRemark, "Worth a look."),
|
|
1010
|
-
mutualIntentsLabel: sanitizePresenterField(parsed.presentation.mutualIntentsLabel,
|
|
843
|
+
mutualIntentsLabel: sanitizePresenterField(parsed.presentation.mutualIntentsLabel, "Shared interests"),
|
|
1011
844
|
greeting: sanitizePresenterField(parsed.presentation.greeting, ""),
|
|
1012
845
|
};
|
|
1013
846
|
const usedFallback = Object.values(fields).some((field) => field.usedFallback);
|
|
1014
847
|
return {
|
|
1015
848
|
headline: fields.headline.value,
|
|
1016
849
|
personalizedSummary: fields.personalizedSummary.value,
|
|
1017
|
-
digestSummary: fields.digestSummary.value,
|
|
1018
850
|
suggestedAction: fields.suggestedAction.value,
|
|
1019
851
|
narratorRemark: fields.narratorRemark.value,
|
|
1020
852
|
mutualIntentsLabel: fields.mutualIntentsLabel.value,
|
|
@@ -1032,24 +864,15 @@ Produce headline, personalizedSummary, digestSummary, suggestedAction, narratorR
|
|
|
1032
864
|
message,
|
|
1033
865
|
timeoutReason,
|
|
1034
866
|
});
|
|
1035
|
-
const fallbackSummary = safeFallbackSummary(input.matchReasoning
|
|
1036
|
-
introducerName: input.isIntroduction ? input.introducerName : undefined,
|
|
1037
|
-
});
|
|
867
|
+
const fallbackSummary = safeFallbackSummary(input.matchReasoning);
|
|
1038
868
|
return {
|
|
1039
869
|
headline: "A promising connection",
|
|
1040
870
|
personalizedSummary: fallbackSummary,
|
|
1041
|
-
|
|
1042
|
-
? "You may be able to help make a useful introduction here."
|
|
1043
|
-
: "You might like meeting them based on your current interests.",
|
|
1044
|
-
suggestedAction: isIntroducer
|
|
1045
|
-
? "Share this introduction to get things started."
|
|
1046
|
-
: "Take a look and decide whether to reach out.",
|
|
871
|
+
suggestedAction: "Take a look and decide whether to reach out.",
|
|
1047
872
|
narratorRemark: "Worth a look.",
|
|
1048
|
-
mutualIntentsLabel:
|
|
1049
|
-
? "
|
|
1050
|
-
:
|
|
1051
|
-
? `${input.mutualIntentCount} mutual intent${input.mutualIntentCount !== 1 ? "s" : ""}`
|
|
1052
|
-
: "Shared interests",
|
|
873
|
+
mutualIntentsLabel: input.mutualIntentCount != null && input.mutualIntentCount > 0
|
|
874
|
+
? `${input.mutualIntentCount} mutual intent${input.mutualIntentCount !== 1 ? "s" : ""}`
|
|
875
|
+
: "Shared interests",
|
|
1053
876
|
greeting: "",
|
|
1054
877
|
isFallback: true,
|
|
1055
878
|
};
|
|
@@ -1119,29 +942,20 @@ __decorate([
|
|
|
1119
942
|
function buildNegotiationPromptBlock(context) {
|
|
1120
943
|
if (!context || context.status === 'negotiating')
|
|
1121
944
|
return "";
|
|
1122
|
-
const
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
const turnLines =
|
|
1130
|
-
const action = turn.action;
|
|
1131
|
-
const reasoning = turn.assessment?.reasoning ?? "(no reasoning)";
|
|
1132
|
-
const message = turn.message ? ` — said: "${turn.message}"` : "";
|
|
1133
|
-
return `Turn ${index + 1} (${action}): ${reasoning}${message}`;
|
|
1134
|
-
});
|
|
1135
|
-
const outcomeSummary = context.outcome
|
|
1136
|
-
? `Final outcome: ${context.outcome.hasOpportunity ? "agreed" : "declined"} — ${context.outcome.reasoning}`
|
|
1137
|
-
: "Final outcome: not recorded.";
|
|
945
|
+
const outcomeLabel = context.outcome === 'agreed'
|
|
946
|
+
? "the agents agreed"
|
|
947
|
+
: context.outcome === 'declined'
|
|
948
|
+
? "one agent declined"
|
|
949
|
+
: context.outcome === 'closed'
|
|
950
|
+
? "the negotiation was closed before it settled"
|
|
951
|
+
: undefined;
|
|
952
|
+
const turnLines = context.turns.map((turn, index) => `Turn ${index + 1} (${turn.action}, ${turn.own ? "your agent" : "their agent"}): "${turn.message}"`);
|
|
1138
953
|
return `
|
|
1139
954
|
NEGOTIATION CONTEXT:
|
|
1140
|
-
- Negotiation status: ${context.status}${
|
|
1141
|
-
- Turns exchanged: ${context.turnCount}
|
|
955
|
+
- Negotiation status: ${context.status}${outcomeLabel ? ` (${outcomeLabel})` : ""}
|
|
956
|
+
- Turns exchanged: ${context.turnCount}
|
|
1142
957
|
- Transcript:
|
|
1143
958
|
${turnLines.length > 0 ? turnLines.map((l) => ` ${l}`).join("\n") : " (no turns recorded)"}
|
|
1144
|
-
- ${outcomeSummary}
|
|
1145
959
|
`;
|
|
1146
960
|
}
|
|
1147
961
|
/**
|
|
@@ -1150,16 +964,11 @@ ${turnLines.length > 0 ? turnLines.map((l) => ` ${l}`).join("\n") : " (no turn
|
|
|
1150
964
|
* negotiating" chip while turns are still being exchanged.
|
|
1151
965
|
*/
|
|
1152
966
|
function buildNegotiatingChip(input) {
|
|
1153
|
-
const
|
|
1154
|
-
const
|
|
1155
|
-
const turnCap = ctx?.turnCap && ctx.turnCap > 0 ? ctx.turnCap : undefined;
|
|
1156
|
-
const narratorRemark = turnCap
|
|
1157
|
-
? `Currently negotiating · turn ${turnCount} of ${turnCap}`
|
|
1158
|
-
: `Currently negotiating · turn ${turnCount}`;
|
|
967
|
+
const turnCount = input.negotiationContext?.turnCount ?? 0;
|
|
968
|
+
const narratorRemark = `Currently negotiating · turn ${turnCount}`;
|
|
1159
969
|
return {
|
|
1160
970
|
headline: "Negotiation in progress",
|
|
1161
971
|
personalizedSummary: "Your agent is still talking with theirs to see if this connection makes sense. We'll surface the full match as soon as they converge.",
|
|
1162
|
-
digestSummary: "Your agent is still checking whether this connection makes sense.",
|
|
1163
972
|
suggestedAction: "Check back shortly — no action needed yet.",
|
|
1164
973
|
narratorRemark,
|
|
1165
974
|
mutualIntentsLabel: input.mutualIntentCount && input.mutualIntentCount > 0
|
|
@@ -1169,7 +978,7 @@ function buildNegotiatingChip(input) {
|
|
|
1169
978
|
};
|
|
1170
979
|
}
|
|
1171
980
|
// ──────────────────────────────────────────────────────────────
|
|
1172
|
-
// CONTEXT GATHERER
|
|
981
|
+
// CONTEXT GATHERER
|
|
1173
982
|
// ──────────────────────────────────────────────────────────────
|
|
1174
983
|
/**
|
|
1175
984
|
* Build the LLM-facing signal summary while excluding pool adjustments. Pool
|
|
@@ -1184,124 +993,36 @@ export function summarizeSignalsForPresenter(signals) {
|
|
|
1184
993
|
}
|
|
1185
994
|
/**
|
|
1186
995
|
* Gather all context needed for the presenter from the database.
|
|
1187
|
-
* Fetches viewer profile, viewer intents, other party profile(s), and
|
|
996
|
+
* Fetches viewer profile, viewer intents, other party profile(s), and network in parallel.
|
|
1188
997
|
*
|
|
1189
|
-
* @param displayCounterpartUserId - When set (e.g. for a radar card), only this counterpart is included in otherPartyContext so the presenter writes about the person on the card.
|
|
998
|
+
* @param displayCounterpartUserId - When set (e.g. for a radar card), only this counterpart is included in otherPartyContext so the presenter writes about the person on the card.
|
|
999
|
+
* @param focusedViewerIntentId - When set, include only that active intent in viewer context.
|
|
1190
1000
|
*/
|
|
1191
|
-
export async function gatherPresenterContext(database, opportunity, viewerId, displayCounterpartUserId) {
|
|
1001
|
+
export async function gatherPresenterContext(database, opportunity, viewerId, displayCounterpartUserId, focusedViewerIntentId) {
|
|
1192
1002
|
const myActor = opportunity.actors.find((a) => a.userId === viewerId);
|
|
1193
1003
|
if (!myActor) {
|
|
1194
1004
|
throw new Error("Viewer is not an actor in this opportunity");
|
|
1195
1005
|
}
|
|
1196
|
-
const isIntroducer = myActor.role === "introducer";
|
|
1197
1006
|
const otherActors = opportunity.actors.filter((a) => a.userId !== viewerId);
|
|
1198
1007
|
let otherPartyIds = [...new Set(otherActors.map((a) => a.userId))];
|
|
1199
|
-
if (displayCounterpartUserId &&
|
|
1200
|
-
!isIntroducer &&
|
|
1201
|
-
otherPartyIds.includes(displayCounterpartUserId)) {
|
|
1008
|
+
if (displayCounterpartUserId && otherPartyIds.includes(displayCounterpartUserId)) {
|
|
1202
1009
|
otherPartyIds = [displayCounterpartUserId];
|
|
1203
1010
|
}
|
|
1204
|
-
const
|
|
1205
|
-
//
|
|
1206
|
-
|
|
1207
|
-
const [viewerProfile, indexRecord, ...otherProfiles] = await Promise.all([
|
|
1011
|
+
const contextNetworkId = opportunity.context?.networkId;
|
|
1012
|
+
// Viewer's profile + intents, plus the other party's profile.
|
|
1013
|
+
const [viewerProfile, networkRecord, ...otherProfiles] = await Promise.all([
|
|
1208
1014
|
database.getProfile(viewerId),
|
|
1209
|
-
|
|
1015
|
+
contextNetworkId ? database.getNetwork(contextNetworkId) : Promise.resolve(null),
|
|
1210
1016
|
...otherPartyIds.map((uid) => database.getProfile(uid)),
|
|
1211
1017
|
]);
|
|
1212
|
-
// Fetch intents: for introducer, fetch each party's intents; otherwise fetch viewer's intents.
|
|
1213
1018
|
let viewerIntents;
|
|
1214
|
-
|
|
1215
|
-
if (
|
|
1216
|
-
|
|
1217
|
-
uid,
|
|
1218
|
-
intents: await database.getActiveIntents(uid),
|
|
1219
|
-
})));
|
|
1220
|
-
partyIntentsMap = new Map(partyIntentResults.map((r) => [r.uid, r.intents]));
|
|
1221
|
-
}
|
|
1222
|
-
else {
|
|
1223
|
-
viewerIntents = await database.getActiveIntents(viewerId);
|
|
1224
|
-
}
|
|
1225
|
-
// Fetch premises when any actor is premise-grounded
|
|
1226
|
-
const premiseGroundedActors = opportunity.actors.filter((a) => a.premise);
|
|
1227
|
-
let viewerPremiseContext = '';
|
|
1228
|
-
let otherPremiseContext = '';
|
|
1229
|
-
if (premiseGroundedActors.length > 0) {
|
|
1230
|
-
// Only fetch premises for actors that are actually premise-grounded, not all parties
|
|
1231
|
-
const groundedOtherIds = premiseGroundedActors
|
|
1232
|
-
.filter((a) => a.userId !== viewerId)
|
|
1233
|
-
.map((a) => a.userId);
|
|
1234
|
-
const viewerIsGrounded = premiseGroundedActors.some((a) => a.userId === viewerId);
|
|
1235
|
-
const results = await Promise.all([
|
|
1236
|
-
...(viewerIsGrounded ? [database.getPremisesForUser(viewerId, 'ACTIVE')] : []),
|
|
1237
|
-
...groundedOtherIds.map((uid) => database.getPremisesForUser(uid, 'ACTIVE')),
|
|
1238
|
-
]);
|
|
1239
|
-
let idx = 0;
|
|
1240
|
-
if (viewerIsGrounded) {
|
|
1241
|
-
const viewerPremises = results[idx++];
|
|
1242
|
-
if (viewerPremises?.length) {
|
|
1243
|
-
viewerPremiseContext =
|
|
1244
|
-
'\nPremises (self-descriptions):\n' +
|
|
1245
|
-
viewerPremises
|
|
1246
|
-
.slice(0, 5)
|
|
1247
|
-
.map((p) => `- ${p.assertion.text}`)
|
|
1248
|
-
.join('\n');
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
const otherPremiseLines = [];
|
|
1252
|
-
for (let i = 0; i < groundedOtherIds.length; i++) {
|
|
1253
|
-
const premises = results[idx++];
|
|
1254
|
-
if (premises?.length) {
|
|
1255
|
-
for (const p of premises.slice(0, 3)) {
|
|
1256
|
-
otherPremiseLines.push(`- ${p.assertion.text}`);
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
if (otherPremiseLines.length > 0) {
|
|
1261
|
-
otherPremiseContext = '\nPremises (self-descriptions):\n' + otherPremiseLines.join('\n');
|
|
1262
|
-
}
|
|
1019
|
+
viewerIntents = await database.getActiveIntents(viewerId);
|
|
1020
|
+
if (focusedViewerIntentId) {
|
|
1021
|
+
viewerIntents = viewerIntents.filter((intent) => intent.id === focusedViewerIntentId);
|
|
1263
1022
|
}
|
|
1264
1023
|
let viewerContext;
|
|
1265
1024
|
let otherPartyContext;
|
|
1266
|
-
|
|
1267
|
-
// Introducer view: minimal viewer context (just name + role), rich other-party context with intents
|
|
1268
|
-
const introducerApproved = opportunity.actors.find(a => a.role === 'introducer')?.approved === true;
|
|
1269
|
-
const hasApproved = introducerApproved || opportunity.status !== 'latent';
|
|
1270
|
-
viewerContext = [
|
|
1271
|
-
"Profile:",
|
|
1272
|
-
`Name: ${viewerProfile?.identity?.name ?? "Unknown"}`,
|
|
1273
|
-
hasApproved
|
|
1274
|
-
? "Role: You are the introducer who suggested this connection."
|
|
1275
|
-
: "Role: You are being asked whether these two people would benefit from meeting. You have NOT yet approved this introduction.",
|
|
1276
|
-
].join("\n");
|
|
1277
|
-
const otherParts = otherPartyIds.map((uid, idx) => {
|
|
1278
|
-
const profile = otherProfiles[idx];
|
|
1279
|
-
const name = profile?.identity?.name ?? "Unknown";
|
|
1280
|
-
const bio = profile?.identity?.bio ?? "";
|
|
1281
|
-
const location = profile?.identity?.location ?? "";
|
|
1282
|
-
const context = profile?.context ?? "";
|
|
1283
|
-
const intents = partyIntentsMap?.get(uid);
|
|
1284
|
-
const intentLines = intents?.length
|
|
1285
|
-
? intents
|
|
1286
|
-
.slice(0, 5)
|
|
1287
|
-
.map((i) => ` - ${i.payload}${i.summary ? ` (${i.summary})` : ""}`)
|
|
1288
|
-
: [" (no active intents)"];
|
|
1289
|
-
return [
|
|
1290
|
-
`${name}:`,
|
|
1291
|
-
` Bio: ${bio}`,
|
|
1292
|
-
location ? ` Location: ${location}` : null,
|
|
1293
|
-
context ? ` Context: ${context}` : null,
|
|
1294
|
-
` Active intents:`,
|
|
1295
|
-
...intentLines,
|
|
1296
|
-
]
|
|
1297
|
-
.filter(Boolean)
|
|
1298
|
-
.join("\n");
|
|
1299
|
-
});
|
|
1300
|
-
otherPartyContext =
|
|
1301
|
-
otherParts.join("\n\n") || "Parties (details not available).";
|
|
1302
|
-
}
|
|
1303
|
-
else {
|
|
1304
|
-
// Non-introducer view: full viewer profile + intents, other party profiles
|
|
1025
|
+
{
|
|
1305
1026
|
const viewerContextLines = [
|
|
1306
1027
|
"Profile:",
|
|
1307
1028
|
`Name: ${viewerProfile?.identity?.name ?? "Unknown"}`,
|
|
@@ -1325,31 +1046,13 @@ export async function gatherPresenterContext(database, opportunity, viewerId, di
|
|
|
1325
1046
|
}
|
|
1326
1047
|
const interp = opportunity.interpretation;
|
|
1327
1048
|
const signalsSummary = summarizeSignalsForPresenter(interp.signals);
|
|
1328
|
-
// Detect introduction-originated opportunities: only when there is an explicit introducer actor.
|
|
1329
|
-
// Do NOT use detection.source === "manual" alone — system-discovered opportunities can have manual source without an introducer.
|
|
1330
|
-
const introducerActor = opportunity.actors.find((a) => a.role === "introducer");
|
|
1331
|
-
const isIntroduction = !!introducerActor;
|
|
1332
|
-
let introducerName;
|
|
1333
|
-
if (introducerActor) {
|
|
1334
|
-
introducerName = opportunity.detection.createdByName;
|
|
1335
|
-
if (!introducerName) {
|
|
1336
|
-
const introducerProfile = await database.getProfile(introducerActor.userId);
|
|
1337
|
-
introducerName = introducerProfile?.identity?.name ?? undefined;
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
1049
|
const counterpartName = otherPartyIds.length === 1 && otherProfiles[0]
|
|
1341
1050
|
? otherProfiles[0]?.identity?.name?.trim()
|
|
1342
1051
|
: undefined;
|
|
1343
1052
|
const viewerNameForFilter = viewerProfile?.identity?.name?.trim();
|
|
1344
1053
|
const matchReasoning = counterpartName && interp.reasoning
|
|
1345
|
-
? viewerCentricCardSummary(interp.reasoning, counterpartName, 400, viewerNameForFilter
|
|
1054
|
+
? viewerCentricCardSummary(interp.reasoning, counterpartName, 400, viewerNameForFilter)
|
|
1346
1055
|
: stripUuids(interp.reasoning);
|
|
1347
|
-
if (viewerPremiseContext) {
|
|
1348
|
-
viewerContext += viewerPremiseContext;
|
|
1349
|
-
}
|
|
1350
|
-
if (otherPremiseContext) {
|
|
1351
|
-
otherPartyContext += otherPremiseContext;
|
|
1352
|
-
}
|
|
1353
1056
|
const result = {
|
|
1354
1057
|
viewerContext,
|
|
1355
1058
|
otherPartyContext,
|
|
@@ -1359,104 +1062,8 @@ export async function gatherPresenterContext(database, opportunity, viewerId, di
|
|
|
1359
1062
|
? interp.confidence
|
|
1360
1063
|
: parseFloat(String(interp.confidence ?? 0)) || 0,
|
|
1361
1064
|
signalsSummary,
|
|
1362
|
-
|
|
1065
|
+
networkName: networkRecord?.title ?? contextNetworkId ?? "",
|
|
1363
1066
|
viewerRole: myActor.role ?? "party",
|
|
1364
|
-
isIntroduction,
|
|
1365
|
-
introducerName,
|
|
1366
1067
|
};
|
|
1367
1068
|
return result;
|
|
1368
1069
|
}
|
|
1369
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
1370
|
-
// ── 5. MCP card prose ──
|
|
1371
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
1372
|
-
const CODE_FENCE = String.fromCharCode(96, 96, 96);
|
|
1373
|
-
function sanitizeJsonForCodeFence(json) {
|
|
1374
|
-
return json.replace(/`/g, '\\u0060');
|
|
1375
|
-
}
|
|
1376
|
-
function sanitizeOpportunityCardProse(card) {
|
|
1377
|
-
const sanitized = { ...card };
|
|
1378
|
-
for (const key of ['mainText', 'digestSummary', 'headline', 'cta', 'mutualIntentsLabel']) {
|
|
1379
|
-
const value = card[key];
|
|
1380
|
-
if (typeof value === 'string') {
|
|
1381
|
-
sanitized[key] = stripUnsupportedOpportunityClaims(stripUuids(value)) || 'A suggested connection.';
|
|
1382
|
-
}
|
|
1383
|
-
}
|
|
1384
|
-
const narratorChip = card.narratorChip;
|
|
1385
|
-
if (narratorChip && typeof narratorChip === 'object' && !Array.isArray(narratorChip)) {
|
|
1386
|
-
const narrator = narratorChip;
|
|
1387
|
-
if (typeof narrator.text === 'string') {
|
|
1388
|
-
sanitized.narratorChip = {
|
|
1389
|
-
...narrator,
|
|
1390
|
-
text: stripUnsupportedOpportunityClaims(stripUuids(narrator.text)) || 'A potential connection worth exploring.',
|
|
1391
|
-
};
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
return sanitized;
|
|
1395
|
-
}
|
|
1396
|
-
/**
|
|
1397
|
-
* Format opportunity cards into the "opportunities" portion of a tool response.
|
|
1398
|
-
*
|
|
1399
|
-
* Web chat (`isMcp=false`): emits ```opportunity``` code fences with an
|
|
1400
|
-
* "include EXACTLY as-is" directive so the frontend card renderer can parse
|
|
1401
|
-
* and render interactive cards.
|
|
1402
|
-
*
|
|
1403
|
-
* MCP (`isMcp=true`): emits prose (name, reason, status, appUrl and profileUrl
|
|
1404
|
-
* when present, feedCategory when present) and includes `opportunityId` for
|
|
1405
|
-
* every card so the agent can act via the tools. The trailing instruction
|
|
1406
|
-
* reminds the agent to synthesize in natural language, to surface the `appUrl`
|
|
1407
|
-
* verbatim as the one link that opens the card, and to fabricate no other URL.
|
|
1408
|
-
* MCP clients have no card renderer, so code fences would surface as raw JSON
|
|
1409
|
-
* to end users.
|
|
1410
|
-
*/
|
|
1411
|
-
export function buildOpportunityPresentation(inputCards, opts) {
|
|
1412
|
-
const cards = inputCards.map(sanitizeOpportunityCardProse);
|
|
1413
|
-
if (cards.length === 0)
|
|
1414
|
-
return opts.leadIn;
|
|
1415
|
-
if (opts.isMcp) {
|
|
1416
|
-
const prose = cards
|
|
1417
|
-
.map((card, i) => {
|
|
1418
|
-
const lines = [`${i + 1}. ${card.name ?? "Unknown"}`];
|
|
1419
|
-
if (opts.includeDigestMarkers) {
|
|
1420
|
-
const markerId = String(card.opportunityId).replace(/[\s>]/g, "");
|
|
1421
|
-
if (markerId)
|
|
1422
|
-
lines.push(` <!-- digest-opportunity:id=${markerId} -->`);
|
|
1423
|
-
}
|
|
1424
|
-
if (opts.includeDigestMarkers && card.digestSummary) {
|
|
1425
|
-
lines.push(` ${card.digestSummary}`);
|
|
1426
|
-
}
|
|
1427
|
-
else if (card.mainText) {
|
|
1428
|
-
lines.push(` ${card.mainText}`);
|
|
1429
|
-
}
|
|
1430
|
-
if (card.status)
|
|
1431
|
-
lines.push(` status: ${card.status}`);
|
|
1432
|
-
if (card.appUrl)
|
|
1433
|
-
lines.push(` appUrl: ${card.appUrl}`);
|
|
1434
|
-
if (card.profileUrl)
|
|
1435
|
-
lines.push(` profileUrl: ${card.profileUrl}`);
|
|
1436
|
-
if (opts.includeDigestMarkers && card.negotiationUrl)
|
|
1437
|
-
lines.push(` negotiationUrl: ${card.negotiationUrl}`);
|
|
1438
|
-
if (card.feedCategory)
|
|
1439
|
-
lines.push(` feedCategory: ${card.feedCategory}`);
|
|
1440
|
-
if (opts.includeDigestMarkers && card.score != null)
|
|
1441
|
-
lines.push(` confidence: ${Math.round(card.score * 100)}`);
|
|
1442
|
-
if (opts.includeDigestMarkers && card.redelivery)
|
|
1443
|
-
lines.push(` redelivery: true`);
|
|
1444
|
-
lines.push(` opportunityId: ${card.opportunityId}`);
|
|
1445
|
-
return lines.join("\n");
|
|
1446
|
-
})
|
|
1447
|
-
.join("\n\n");
|
|
1448
|
-
const idInstructions = `Use opportunityId values only when calling update_opportunity (send/accept/reject) or confirm_opportunity_delivery.`;
|
|
1449
|
-
return (`${opts.leadIn}\n\n${prose}\n\n` +
|
|
1450
|
-
`Summarize these for the user in natural prose — mention first names and a brief match reason per connection. ` +
|
|
1451
|
-
`For each card that has a profileUrl, link the person's name to it. Some cards may have no URL — render those as plain text and never fabricate URLs for them. ` +
|
|
1452
|
-
`For each card that has an appUrl, show that link so the user can open the opportunity: it opens the card in the Index app when installed, and an Index web page otherwise. Show only an appUrl a tool returned — never assemble one from an opportunityId. ` +
|
|
1453
|
-
`No link accepts on the user's behalf: accepting happens in the Index app (or via update_opportunity) — never invent an accept URL. ` +
|
|
1454
|
-
`Do NOT print raw JSON, field labels, or opportunityIds. ` +
|
|
1455
|
-
`${idInstructions}`);
|
|
1456
|
-
}
|
|
1457
|
-
const label = opts.label ?? (cards.length === 1 ? "opportunity" : "opportunities");
|
|
1458
|
-
const blocks = cards
|
|
1459
|
-
.map((card) => CODE_FENCE + "opportunity\n" + sanitizeJsonForCodeFence(JSON.stringify(card)) + "\n" + CODE_FENCE)
|
|
1460
|
-
.join("\n\n");
|
|
1461
|
-
return (`${opts.leadIn} IMPORTANT: Include the following ${CODE_FENCE}${label} code blocks EXACTLY as-is in your response (they render as interactive cards):\n\n${blocks}`);
|
|
1462
|
-
}
|