@indexnetwork/protocol 0.1.0
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/dist/agents/chat.agent.d.ts +218 -0
- package/dist/agents/chat.agent.d.ts.map +1 -0
- package/dist/agents/chat.agent.js +884 -0
- package/dist/agents/chat.agent.js.map +1 -0
- package/dist/agents/chat.prompt.d.ts +18 -0
- package/dist/agents/chat.prompt.d.ts.map +1 -0
- package/dist/agents/chat.prompt.js +372 -0
- package/dist/agents/chat.prompt.js.map +1 -0
- package/dist/agents/chat.prompt.modules.d.ts +61 -0
- package/dist/agents/chat.prompt.modules.d.ts.map +1 -0
- package/dist/agents/chat.prompt.modules.js +366 -0
- package/dist/agents/chat.prompt.modules.js.map +1 -0
- package/dist/agents/chat.title.generator.d.ts +20 -0
- package/dist/agents/chat.title.generator.d.ts.map +1 -0
- package/dist/agents/chat.title.generator.js +66 -0
- package/dist/agents/chat.title.generator.js.map +1 -0
- package/dist/agents/home.categorizer.d.ts +28 -0
- package/dist/agents/home.categorizer.d.ts.map +1 -0
- package/dist/agents/home.categorizer.js +170 -0
- package/dist/agents/home.categorizer.js.map +1 -0
- package/dist/agents/hyde.generator.d.ts +27 -0
- package/dist/agents/hyde.generator.d.ts.map +1 -0
- package/dist/agents/hyde.generator.js +75 -0
- package/dist/agents/hyde.generator.js.map +1 -0
- package/dist/agents/hyde.strategies.d.ts +17 -0
- package/dist/agents/hyde.strategies.d.ts.map +1 -0
- package/dist/agents/hyde.strategies.js +29 -0
- package/dist/agents/hyde.strategies.js.map +1 -0
- package/dist/agents/intent.clarifier.d.ts +29 -0
- package/dist/agents/intent.clarifier.d.ts.map +1 -0
- package/dist/agents/intent.clarifier.js +186 -0
- package/dist/agents/intent.clarifier.js.map +1 -0
- package/dist/agents/intent.indexer.d.ts +77 -0
- package/dist/agents/intent.indexer.d.ts.map +1 -0
- package/dist/agents/intent.indexer.js +164 -0
- package/dist/agents/intent.indexer.js.map +1 -0
- package/dist/agents/intent.inferrer.d.ts +95 -0
- package/dist/agents/intent.inferrer.d.ts.map +1 -0
- package/dist/agents/intent.inferrer.js +238 -0
- package/dist/agents/intent.inferrer.js.map +1 -0
- package/dist/agents/intent.reconciler.d.ts +106 -0
- package/dist/agents/intent.reconciler.d.ts.map +1 -0
- package/dist/agents/intent.reconciler.js +184 -0
- package/dist/agents/intent.reconciler.js.map +1 -0
- package/dist/agents/intent.verifier.d.ts +97 -0
- package/dist/agents/intent.verifier.d.ts.map +1 -0
- package/dist/agents/intent.verifier.js +234 -0
- package/dist/agents/intent.verifier.js.map +1 -0
- package/dist/agents/invite.generator.d.ts +47 -0
- package/dist/agents/invite.generator.d.ts.map +1 -0
- package/dist/agents/invite.generator.js +56 -0
- package/dist/agents/invite.generator.js.map +1 -0
- package/dist/agents/lens.inferrer.d.ts +37 -0
- package/dist/agents/lens.inferrer.d.ts.map +1 -0
- package/dist/agents/lens.inferrer.js +98 -0
- package/dist/agents/lens.inferrer.js.map +1 -0
- package/dist/agents/model.config.d.ts +120 -0
- package/dist/agents/model.config.d.ts.map +1 -0
- package/dist/agents/model.config.js +76 -0
- package/dist/agents/model.config.js.map +1 -0
- package/dist/agents/negotiation.insights.generator.d.ts +32 -0
- package/dist/agents/negotiation.insights.generator.d.ts.map +1 -0
- package/dist/agents/negotiation.insights.generator.js +105 -0
- package/dist/agents/negotiation.insights.generator.js.map +1 -0
- package/dist/agents/negotiation.proposer.d.ts +26 -0
- package/dist/agents/negotiation.proposer.d.ts.map +1 -0
- package/dist/agents/negotiation.proposer.js +67 -0
- package/dist/agents/negotiation.proposer.js.map +1 -0
- package/dist/agents/negotiation.responder.d.ts +26 -0
- package/dist/agents/negotiation.responder.d.ts.map +1 -0
- package/dist/agents/negotiation.responder.js +71 -0
- package/dist/agents/negotiation.responder.js.map +1 -0
- package/dist/agents/opportunity.evaluator.d.ts +253 -0
- package/dist/agents/opportunity.evaluator.d.ts.map +1 -0
- package/dist/agents/opportunity.evaluator.js +413 -0
- package/dist/agents/opportunity.evaluator.js.map +1 -0
- package/dist/agents/opportunity.presenter.d.ts +115 -0
- package/dist/agents/opportunity.presenter.d.ts.map +1 -0
- package/dist/agents/opportunity.presenter.js +524 -0
- package/dist/agents/opportunity.presenter.js.map +1 -0
- package/dist/agents/profile.generator.d.ts +67 -0
- package/dist/agents/profile.generator.d.ts.map +1 -0
- package/dist/agents/profile.generator.js +97 -0
- package/dist/agents/profile.generator.js.map +1 -0
- package/dist/agents/profile.hyde.generator.d.ts +43 -0
- package/dist/agents/profile.hyde.generator.d.ts.map +1 -0
- package/dist/agents/profile.hyde.generator.js +113 -0
- package/dist/agents/profile.hyde.generator.js.map +1 -0
- package/dist/agents/suggestion.generator.d.ts +24 -0
- package/dist/agents/suggestion.generator.d.ts.map +1 -0
- package/dist/agents/suggestion.generator.js +96 -0
- package/dist/agents/suggestion.generator.js.map +1 -0
- package/dist/graphs/chat.graph.d.ts +312 -0
- package/dist/graphs/chat.graph.d.ts.map +1 -0
- package/dist/graphs/chat.graph.js +267 -0
- package/dist/graphs/chat.graph.js.map +1 -0
- package/dist/graphs/home.graph.d.ts +180 -0
- package/dist/graphs/home.graph.d.ts.map +1 -0
- package/dist/graphs/home.graph.js +598 -0
- package/dist/graphs/home.graph.js.map +1 -0
- package/dist/graphs/hyde.graph.d.ts +110 -0
- package/dist/graphs/hyde.graph.d.ts.map +1 -0
- package/dist/graphs/hyde.graph.js +235 -0
- package/dist/graphs/hyde.graph.js.map +1 -0
- package/dist/graphs/index.graph.d.ts +620 -0
- package/dist/graphs/index.graph.d.ts.map +1 -0
- package/dist/graphs/index.graph.js +226 -0
- package/dist/graphs/index.graph.js.map +1 -0
- package/dist/graphs/index_membership.graph.d.ts +250 -0
- package/dist/graphs/index_membership.graph.d.ts.map +1 -0
- package/dist/graphs/index_membership.graph.js +204 -0
- package/dist/graphs/index_membership.graph.js.map +1 -0
- package/dist/graphs/intent.graph.d.ts +490 -0
- package/dist/graphs/intent.graph.d.ts.map +1 -0
- package/dist/graphs/intent.graph.js +787 -0
- package/dist/graphs/intent.graph.js.map +1 -0
- package/dist/graphs/intent_index.graph.d.ts +396 -0
- package/dist/graphs/intent_index.graph.d.ts.map +1 -0
- package/dist/graphs/intent_index.graph.js +331 -0
- package/dist/graphs/intent_index.graph.js.map +1 -0
- package/dist/graphs/maintenance.graph.d.ts +177 -0
- package/dist/graphs/maintenance.graph.d.ts.map +1 -0
- package/dist/graphs/maintenance.graph.js +173 -0
- package/dist/graphs/maintenance.graph.js.map +1 -0
- package/dist/graphs/negotiation.graph.d.ts +819 -0
- package/dist/graphs/negotiation.graph.d.ts.map +1 -0
- package/dist/graphs/negotiation.graph.js +255 -0
- package/dist/graphs/negotiation.graph.js.map +1 -0
- package/dist/graphs/opportunity.graph.d.ts +1082 -0
- package/dist/graphs/opportunity.graph.d.ts.map +1 -0
- package/dist/graphs/opportunity.graph.js +2534 -0
- package/dist/graphs/opportunity.graph.js.map +1 -0
- package/dist/graphs/profile.graph.d.ts +617 -0
- package/dist/graphs/profile.graph.d.ts.map +1 -0
- package/dist/graphs/profile.graph.js +839 -0
- package/dist/graphs/profile.graph.js.map +1 -0
- package/dist/graphs/tests/chat.graph.mocks.d.ts +104 -0
- package/dist/graphs/tests/chat.graph.mocks.d.ts.map +1 -0
- package/dist/graphs/tests/chat.graph.mocks.js +225 -0
- package/dist/graphs/tests/chat.graph.mocks.js.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/auth.interface.d.ts +15 -0
- package/dist/interfaces/auth.interface.d.ts.map +1 -0
- package/dist/interfaces/auth.interface.js +2 -0
- package/dist/interfaces/auth.interface.js.map +1 -0
- package/dist/interfaces/cache.interface.d.ts +43 -0
- package/dist/interfaces/cache.interface.d.ts.map +1 -0
- package/dist/interfaces/cache.interface.js +6 -0
- package/dist/interfaces/cache.interface.js.map +1 -0
- package/dist/interfaces/chat-session.interface.d.ts +11 -0
- package/dist/interfaces/chat-session.interface.d.ts.map +1 -0
- package/dist/interfaces/chat-session.interface.js +2 -0
- package/dist/interfaces/chat-session.interface.js.map +1 -0
- package/dist/interfaces/contact.interface.d.ts +48 -0
- package/dist/interfaces/contact.interface.d.ts.map +1 -0
- package/dist/interfaces/contact.interface.js +2 -0
- package/dist/interfaces/contact.interface.js.map +1 -0
- package/dist/interfaces/database.interface.d.ts +1495 -0
- package/dist/interfaces/database.interface.d.ts.map +1 -0
- package/dist/interfaces/database.interface.js +2 -0
- package/dist/interfaces/database.interface.js.map +1 -0
- package/dist/interfaces/embedder.interface.d.ts +85 -0
- package/dist/interfaces/embedder.interface.d.ts.map +1 -0
- package/dist/interfaces/embedder.interface.js +5 -0
- package/dist/interfaces/embedder.interface.js.map +1 -0
- package/dist/interfaces/enrichment.interface.d.ts +40 -0
- package/dist/interfaces/enrichment.interface.d.ts.map +1 -0
- package/dist/interfaces/enrichment.interface.js +2 -0
- package/dist/interfaces/enrichment.interface.js.map +1 -0
- package/dist/interfaces/integration.interface.d.ts +91 -0
- package/dist/interfaces/integration.interface.d.ts.map +1 -0
- package/dist/interfaces/integration.interface.js +2 -0
- package/dist/interfaces/integration.interface.js.map +1 -0
- package/dist/interfaces/queue.interface.d.ts +17 -0
- package/dist/interfaces/queue.interface.d.ts.map +1 -0
- package/dist/interfaces/queue.interface.js +5 -0
- package/dist/interfaces/queue.interface.js.map +1 -0
- package/dist/interfaces/scraper.interface.d.ts +31 -0
- package/dist/interfaces/scraper.interface.d.ts.map +1 -0
- package/dist/interfaces/scraper.interface.js +2 -0
- package/dist/interfaces/scraper.interface.js.map +1 -0
- package/dist/interfaces/storage.interface.d.ts +46 -0
- package/dist/interfaces/storage.interface.d.ts.map +1 -0
- package/dist/interfaces/storage.interface.js +6 -0
- package/dist/interfaces/storage.interface.js.map +1 -0
- package/dist/mcp/mcp.server.d.ts +29 -0
- package/dist/mcp/mcp.server.d.ts.map +1 -0
- package/dist/mcp/mcp.server.js +171 -0
- package/dist/mcp/mcp.server.js.map +1 -0
- package/dist/states/chat.state.d.ts +126 -0
- package/dist/states/chat.state.d.ts.map +1 -0
- package/dist/states/chat.state.js +112 -0
- package/dist/states/chat.state.js.map +1 -0
- package/dist/states/home.state.d.ts +100 -0
- package/dist/states/home.state.d.ts.map +1 -0
- package/dist/states/home.state.js +74 -0
- package/dist/states/home.state.js.map +1 -0
- package/dist/states/hyde.state.d.ts +54 -0
- package/dist/states/hyde.state.d.ts.map +1 -0
- package/dist/states/hyde.state.js +66 -0
- package/dist/states/hyde.state.js.map +1 -0
- package/dist/states/index.state.d.ts +179 -0
- package/dist/states/index.state.d.ts.map +1 -0
- package/dist/states/index.state.js +56 -0
- package/dist/states/index.state.js.map +1 -0
- package/dist/states/index_membership.state.d.ts +77 -0
- package/dist/states/index_membership.state.d.ts.map +1 -0
- package/dist/states/index_membership.state.js +43 -0
- package/dist/states/index_membership.state.js.map +1 -0
- package/dist/states/intent.state.d.ts +203 -0
- package/dist/states/intent.state.d.ts.map +1 -0
- package/dist/states/intent.state.js +153 -0
- package/dist/states/intent.state.js.map +1 -0
- package/dist/states/intent_index.state.d.ts +148 -0
- package/dist/states/intent_index.state.d.ts.map +1 -0
- package/dist/states/intent_index.state.js +100 -0
- package/dist/states/intent_index.state.js.map +1 -0
- package/dist/states/maintenance.state.d.ts +36 -0
- package/dist/states/maintenance.state.d.ts.map +1 -0
- package/dist/states/maintenance.state.js +56 -0
- package/dist/states/maintenance.state.js.map +1 -0
- package/dist/states/negotiation.state.d.ts +230 -0
- package/dist/states/negotiation.state.d.ts.map +1 -0
- package/dist/states/negotiation.state.js +82 -0
- package/dist/states/negotiation.state.js.map +1 -0
- package/dist/states/opportunity.state.d.ts +300 -0
- package/dist/states/opportunity.state.d.ts.map +1 -0
- package/dist/states/opportunity.state.js +207 -0
- package/dist/states/opportunity.state.js.map +1 -0
- package/dist/states/profile.state.d.ts +172 -0
- package/dist/states/profile.state.d.ts.map +1 -0
- package/dist/states/profile.state.js +133 -0
- package/dist/states/profile.state.js.map +1 -0
- package/dist/streamers/chat.streamer.d.ts +55 -0
- package/dist/streamers/chat.streamer.d.ts.map +1 -0
- package/dist/streamers/chat.streamer.js +186 -0
- package/dist/streamers/chat.streamer.js.map +1 -0
- package/dist/streamers/index.d.ts +3 -0
- package/dist/streamers/index.d.ts.map +1 -0
- package/dist/streamers/index.js +3 -0
- package/dist/streamers/index.js.map +1 -0
- package/dist/streamers/response.streamer.d.ts +36 -0
- package/dist/streamers/response.streamer.d.ts.map +1 -0
- package/dist/streamers/response.streamer.js +46 -0
- package/dist/streamers/response.streamer.js.map +1 -0
- package/dist/support/chat.utils.d.ts +42 -0
- package/dist/support/chat.utils.d.ts.map +1 -0
- package/dist/support/chat.utils.js +89 -0
- package/dist/support/chat.utils.js.map +1 -0
- package/dist/support/debug-meta.sanitizer.d.ts +18 -0
- package/dist/support/debug-meta.sanitizer.d.ts.map +1 -0
- package/dist/support/debug-meta.sanitizer.js +82 -0
- package/dist/support/debug-meta.sanitizer.js.map +1 -0
- package/dist/support/feed.health.d.ts +32 -0
- package/dist/support/feed.health.d.ts.map +1 -0
- package/dist/support/feed.health.js +76 -0
- package/dist/support/feed.health.js.map +1 -0
- package/dist/support/introducer.discovery.d.ts +78 -0
- package/dist/support/introducer.discovery.d.ts.map +1 -0
- package/dist/support/introducer.discovery.js +101 -0
- package/dist/support/introducer.discovery.js.map +1 -0
- package/dist/support/log.d.ts +65 -0
- package/dist/support/log.d.ts.map +1 -0
- package/dist/support/log.js +76 -0
- package/dist/support/log.js.map +1 -0
- package/dist/support/lucide.icon-catalog.d.ts +22 -0
- package/dist/support/lucide.icon-catalog.d.ts.map +1 -0
- package/dist/support/lucide.icon-catalog.js +101 -0
- package/dist/support/lucide.icon-catalog.js.map +1 -0
- package/dist/support/opportunity.card-text.d.ts +39 -0
- package/dist/support/opportunity.card-text.d.ts.map +1 -0
- package/dist/support/opportunity.card-text.js +333 -0
- package/dist/support/opportunity.card-text.js.map +1 -0
- package/dist/support/opportunity.constants.d.ts +9 -0
- package/dist/support/opportunity.constants.d.ts.map +1 -0
- package/dist/support/opportunity.constants.js +11 -0
- package/dist/support/opportunity.constants.js.map +1 -0
- package/dist/support/opportunity.discover.d.ts +144 -0
- package/dist/support/opportunity.discover.d.ts.map +1 -0
- package/dist/support/opportunity.discover.js +610 -0
- package/dist/support/opportunity.discover.js.map +1 -0
- package/dist/support/opportunity.enricher.d.ts +44 -0
- package/dist/support/opportunity.enricher.d.ts.map +1 -0
- package/dist/support/opportunity.enricher.js +245 -0
- package/dist/support/opportunity.enricher.js.map +1 -0
- package/dist/support/opportunity.persist.d.ts +39 -0
- package/dist/support/opportunity.persist.d.ts.map +1 -0
- package/dist/support/opportunity.persist.js +63 -0
- package/dist/support/opportunity.persist.js.map +1 -0
- package/dist/support/opportunity.presentation.d.ts +21 -0
- package/dist/support/opportunity.presentation.d.ts.map +1 -0
- package/dist/support/opportunity.presentation.js +75 -0
- package/dist/support/opportunity.presentation.js.map +1 -0
- package/dist/support/opportunity.sanitize.d.ts +18 -0
- package/dist/support/opportunity.sanitize.d.ts.map +1 -0
- package/dist/support/opportunity.sanitize.js +89 -0
- package/dist/support/opportunity.sanitize.js.map +1 -0
- package/dist/support/opportunity.utils.d.ts +99 -0
- package/dist/support/opportunity.utils.d.ts.map +1 -0
- package/dist/support/opportunity.utils.js +184 -0
- package/dist/support/opportunity.utils.js.map +1 -0
- package/dist/support/performance.d.ts +19 -0
- package/dist/support/performance.d.ts.map +1 -0
- package/dist/support/performance.js +43 -0
- package/dist/support/performance.js.map +1 -0
- package/dist/support/profile.enrichment-display-name.d.ts +16 -0
- package/dist/support/profile.enrichment-display-name.d.ts.map +1 -0
- package/dist/support/profile.enrichment-display-name.js +22 -0
- package/dist/support/profile.enrichment-display-name.js.map +1 -0
- package/dist/support/protocol.logger.d.ts +22 -0
- package/dist/support/protocol.logger.d.ts.map +1 -0
- package/dist/support/protocol.logger.js +44 -0
- package/dist/support/protocol.logger.js.map +1 -0
- package/dist/support/request-context.d.ts +19 -0
- package/dist/support/request-context.d.ts.map +1 -0
- package/dist/support/request-context.js +7 -0
- package/dist/support/request-context.js.map +1 -0
- package/dist/tools/contact.tools.d.ts +7 -0
- package/dist/tools/contact.tools.d.ts.map +1 -0
- package/dist/tools/contact.tools.js +115 -0
- package/dist/tools/contact.tools.js.map +1 -0
- package/dist/tools/index.d.ts +17 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +140 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/index.tools.d.ts +3 -0
- package/dist/tools/index.tools.d.ts.map +1 -0
- package/dist/tools/index.tools.js +423 -0
- package/dist/tools/index.tools.js.map +1 -0
- package/dist/tools/integration.tools.d.ts +13 -0
- package/dist/tools/integration.tools.d.ts.map +1 -0
- package/dist/tools/integration.tools.js +77 -0
- package/dist/tools/integration.tools.js.map +1 -0
- package/dist/tools/intent.tools.d.ts +3 -0
- package/dist/tools/intent.tools.d.ts.map +1 -0
- package/dist/tools/intent.tools.js +458 -0
- package/dist/tools/intent.tools.js.map +1 -0
- package/dist/tools/opportunity.tools.d.ts +44 -0
- package/dist/tools/opportunity.tools.d.ts.map +1 -0
- package/dist/tools/opportunity.tools.js +814 -0
- package/dist/tools/opportunity.tools.js.map +1 -0
- package/dist/tools/profile.tools.d.ts +3 -0
- package/dist/tools/profile.tools.d.ts.map +1 -0
- package/dist/tools/profile.tools.js +513 -0
- package/dist/tools/profile.tools.js.map +1 -0
- package/dist/tools/tool.helpers.d.ts +225 -0
- package/dist/tools/tool.helpers.d.ts.map +1 -0
- package/dist/tools/tool.helpers.js +172 -0
- package/dist/tools/tool.helpers.js.map +1 -0
- package/dist/tools/tool.registry.d.ts +12 -0
- package/dist/tools/tool.registry.d.ts.map +1 -0
- package/dist/tools/tool.registry.js +62 -0
- package/dist/tools/tool.registry.js.map +1 -0
- package/dist/tools/utility.tools.d.ts +3 -0
- package/dist/tools/utility.tools.d.ts.map +1 -0
- package/dist/tools/utility.tools.js +107 -0
- package/dist/tools/utility.tools.js.map +1 -0
- package/dist/types/chat-streaming.types.d.ts +472 -0
- package/dist/types/chat-streaming.types.d.ts.map +1 -0
- package/dist/types/chat-streaming.types.js +260 -0
- package/dist/types/chat-streaming.types.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createTokenEvent, createErrorEvent, } from "../types/chat-streaming.types.js";
|
|
2
|
+
import { protocolLogger } from "../support/protocol.logger.js";
|
|
3
|
+
const logger = protocolLogger("ResponseStreamer");
|
|
4
|
+
// ══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
// RESPONSE STREAMER
|
|
6
|
+
// ══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
/**
|
|
8
|
+
* Streams the final response from the chat agent.
|
|
9
|
+
*
|
|
10
|
+
* Processes the `on_chain_end` event emitted by the `agent_loop` node and
|
|
11
|
+
* yields either a token event (with the full response text) or an error event.
|
|
12
|
+
*
|
|
13
|
+
* Note on token streaming:
|
|
14
|
+
* We do NOT emit from `on_chat_model_stream` because `streamEvents` yields
|
|
15
|
+
* events from ALL model invocations, including nested ones
|
|
16
|
+
* (ExplicitIntentInferrer, SemanticVerifier, IntentReconciler, IntentIndexer)
|
|
17
|
+
* inside tools. Those emit structured JSON that must not reach the user. The
|
|
18
|
+
* chat agent uses `model.invoke()` so we don't get token-by-token streaming
|
|
19
|
+
* anyway. We only emit the clean final response from `on_chain_end`.
|
|
20
|
+
*/
|
|
21
|
+
export class ResponseStreamer {
|
|
22
|
+
/**
|
|
23
|
+
* Processes an `on_chain_end` event whose name is `agent_loop`.
|
|
24
|
+
*
|
|
25
|
+
* @returns An array of stream events to yield (token and/or error), plus
|
|
26
|
+
* metadata for the caller to log.
|
|
27
|
+
*/
|
|
28
|
+
handleAgentLoopEnd(sessionId, event) {
|
|
29
|
+
const output = event.data?.output;
|
|
30
|
+
const responseText = typeof output?.responseText === "string" ? output.responseText : "";
|
|
31
|
+
const agentError = typeof output?.error === "string" ? output.error : undefined;
|
|
32
|
+
logger.debug("Agent loop output", { output, responseText, agentError });
|
|
33
|
+
const events = [];
|
|
34
|
+
if (agentError) {
|
|
35
|
+
logger.warn("Agent loop returned error", { agentError });
|
|
36
|
+
events.push(createErrorEvent(sessionId, agentError === "JSON error injected into SSE stream"
|
|
37
|
+
? "The response could not be sent correctly. Please try again."
|
|
38
|
+
: agentError, "AGENT_ERROR"));
|
|
39
|
+
}
|
|
40
|
+
if (responseText) {
|
|
41
|
+
events.push(createTokenEvent(sessionId, responseText));
|
|
42
|
+
}
|
|
43
|
+
return { events, responseText, hadError: !!agentError };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=response.streamer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.streamer.js","sourceRoot":"","sources":["../../src/streamers/response.streamer.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,MAAM,GAAG,cAAc,CAAC,kBAAkB,CAAC,CAAC;AAElD,iFAAiF;AACjF,oBAAoB;AACpB,iFAAiF;AAEjF;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,gBAAgB;IAC3B;;;;;OAKG;IACH,kBAAkB,CAChB,SAAiB,EACjB,KAAwE;QAExE,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC;QAClC,MAAM,YAAY,GAAG,OAAO,MAAM,EAAE,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QACzF,MAAM,UAAU,GAAG,OAAO,MAAM,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAEhF,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC;QAExE,MAAM,MAAM,GAAsB,EAAE,CAAC;QAErC,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YACzD,MAAM,CAAC,IAAI,CACT,gBAAgB,CACd,SAAS,EACT,UAAU,KAAK,qCAAqC;gBAClD,CAAC,CAAC,6DAA6D;gBAC/D,CAAC,CAAC,UAAU,EACd,aAAa,CACd,CACF,CAAC;QACJ,CAAC;QAED,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC;IAC1D,CAAC;CACF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token utilities for context window management.
|
|
3
|
+
* Estimates token counts and truncates message arrays to fit within model limits.
|
|
4
|
+
* Uses a simple heuristic (~4 chars per token for English).
|
|
5
|
+
*/
|
|
6
|
+
import { BaseMessage } from "@langchain/core/messages";
|
|
7
|
+
/**
|
|
8
|
+
* Default maximum tokens to allow for context.
|
|
9
|
+
* Reserves space for system prompt and response generation.
|
|
10
|
+
*/
|
|
11
|
+
export declare const MAX_CONTEXT_TOKENS = 8000;
|
|
12
|
+
/**
|
|
13
|
+
* Estimate token count for a string using a simple heuristic.
|
|
14
|
+
*
|
|
15
|
+
* This uses a rough estimate of ~4 characters per token, which works
|
|
16
|
+
* reasonably well for English text. For more accuracy with specific
|
|
17
|
+
* models, use tiktoken or the model's native tokenizer.
|
|
18
|
+
*
|
|
19
|
+
* @param text - The text to estimate tokens for
|
|
20
|
+
* @returns Estimated token count
|
|
21
|
+
*/
|
|
22
|
+
export declare function estimateTokenCount(text: string): number;
|
|
23
|
+
/**
|
|
24
|
+
* Estimate token count for a message, including role overhead.
|
|
25
|
+
*
|
|
26
|
+
* @param message - The LangChain message to estimate
|
|
27
|
+
* @returns Estimated token count including message overhead
|
|
28
|
+
*/
|
|
29
|
+
export declare function estimateMessageTokens(message: BaseMessage): number;
|
|
30
|
+
/**
|
|
31
|
+
* Truncate messages to fit within token limit, keeping most recent messages.
|
|
32
|
+
*
|
|
33
|
+
* Messages are processed from newest to oldest, accumulating until the
|
|
34
|
+
* token limit is reached. The first message (usually system) is always
|
|
35
|
+
* kept if present.
|
|
36
|
+
*
|
|
37
|
+
* @param messages - Array of messages to truncate
|
|
38
|
+
* @param maxTokens - Maximum total tokens allowed (default: MAX_CONTEXT_TOKENS)
|
|
39
|
+
* @returns Array of messages that fit within the token limit
|
|
40
|
+
*/
|
|
41
|
+
export declare function truncateToTokenLimit(messages: BaseMessage[], maxTokens?: number): BaseMessage[];
|
|
42
|
+
//# sourceMappingURL=chat.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.utils.d.ts","sourceRoot":"","sources":["../../src/support/chat.utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAKvC;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAQlE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,WAAW,EAAE,EACvB,SAAS,GAAE,MAA2B,GACrC,WAAW,EAAE,CA2Cf"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token utilities for context window management.
|
|
3
|
+
* Estimates token counts and truncates message arrays to fit within model limits.
|
|
4
|
+
* Uses a simple heuristic (~4 chars per token for English).
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Default maximum tokens to allow for context.
|
|
8
|
+
* Reserves space for system prompt and response generation.
|
|
9
|
+
*/
|
|
10
|
+
export const MAX_CONTEXT_TOKENS = 8000;
|
|
11
|
+
/** Minimum tokens to reserve for the model's response (internal use in truncateToTokenLimit). */
|
|
12
|
+
const RESERVED_RESPONSE_TOKENS = 2000;
|
|
13
|
+
/**
|
|
14
|
+
* Estimate token count for a string using a simple heuristic.
|
|
15
|
+
*
|
|
16
|
+
* This uses a rough estimate of ~4 characters per token, which works
|
|
17
|
+
* reasonably well for English text. For more accuracy with specific
|
|
18
|
+
* models, use tiktoken or the model's native tokenizer.
|
|
19
|
+
*
|
|
20
|
+
* @param text - The text to estimate tokens for
|
|
21
|
+
* @returns Estimated token count
|
|
22
|
+
*/
|
|
23
|
+
export function estimateTokenCount(text) {
|
|
24
|
+
if (!text)
|
|
25
|
+
return 0;
|
|
26
|
+
// Rough estimate: ~4 characters per token for English
|
|
27
|
+
// This tends to slightly overestimate, which is safer for truncation
|
|
28
|
+
return Math.ceil(text.length / 4);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Estimate token count for a message, including role overhead.
|
|
32
|
+
*
|
|
33
|
+
* @param message - The LangChain message to estimate
|
|
34
|
+
* @returns Estimated token count including message overhead
|
|
35
|
+
*/
|
|
36
|
+
export function estimateMessageTokens(message) {
|
|
37
|
+
const content = typeof message.content === "string"
|
|
38
|
+
? message.content
|
|
39
|
+
: JSON.stringify(message.content);
|
|
40
|
+
// Add ~4 tokens overhead per message for role and formatting
|
|
41
|
+
return estimateTokenCount(content) + 4;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Truncate messages to fit within token limit, keeping most recent messages.
|
|
45
|
+
*
|
|
46
|
+
* Messages are processed from newest to oldest, accumulating until the
|
|
47
|
+
* token limit is reached. The first message (usually system) is always
|
|
48
|
+
* kept if present.
|
|
49
|
+
*
|
|
50
|
+
* @param messages - Array of messages to truncate
|
|
51
|
+
* @param maxTokens - Maximum total tokens allowed (default: MAX_CONTEXT_TOKENS)
|
|
52
|
+
* @returns Array of messages that fit within the token limit
|
|
53
|
+
*/
|
|
54
|
+
export function truncateToTokenLimit(messages, maxTokens = MAX_CONTEXT_TOKENS) {
|
|
55
|
+
if (messages.length === 0)
|
|
56
|
+
return [];
|
|
57
|
+
// Calculate available tokens (reserve space for response)
|
|
58
|
+
const availableTokens = maxTokens - RESERVED_RESPONSE_TOKENS;
|
|
59
|
+
// If only one message, return it (truncation within message not supported)
|
|
60
|
+
if (messages.length === 1) {
|
|
61
|
+
return messages;
|
|
62
|
+
}
|
|
63
|
+
let totalTokens = 0;
|
|
64
|
+
const result = [];
|
|
65
|
+
// Check if first message is a system message (should always be kept)
|
|
66
|
+
const firstMessage = messages[0];
|
|
67
|
+
const hasSystemMessage = firstMessage._getType() === "system";
|
|
68
|
+
if (hasSystemMessage) {
|
|
69
|
+
const systemTokens = estimateMessageTokens(firstMessage);
|
|
70
|
+
totalTokens += systemTokens;
|
|
71
|
+
result.push(firstMessage);
|
|
72
|
+
}
|
|
73
|
+
// Process remaining messages from newest to oldest
|
|
74
|
+
const remainingMessages = hasSystemMessage ? messages.slice(1) : messages;
|
|
75
|
+
const recentMessages = [];
|
|
76
|
+
for (let i = remainingMessages.length - 1; i >= 0; i--) {
|
|
77
|
+
const msg = remainingMessages[i];
|
|
78
|
+
const msgTokens = estimateMessageTokens(msg);
|
|
79
|
+
if (totalTokens + msgTokens > availableTokens) {
|
|
80
|
+
// Stop adding more messages
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
recentMessages.unshift(msg);
|
|
84
|
+
totalTokens += msgTokens;
|
|
85
|
+
}
|
|
86
|
+
// Combine system message (if any) with recent messages
|
|
87
|
+
return hasSystemMessage ? [firstMessage, ...recentMessages] : recentMessages;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=chat.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.utils.js","sourceRoot":"","sources":["../../src/support/chat.utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEvC,iGAAiG;AACjG,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAEtC;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,CAAC;IACpB,sDAAsD;IACtD,qEAAqE;IACrE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAoB;IACxD,MAAM,OAAO,GACX,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ;QACjC,CAAC,CAAC,OAAO,CAAC,OAAO;QACjB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAEtC,6DAA6D;IAC7D,OAAO,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAuB,EACvB,YAAoB,kBAAkB;IAEtC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,0DAA0D;IAC1D,MAAM,eAAe,GAAG,SAAS,GAAG,wBAAwB,CAAC;IAE7D,2EAA2E;IAC3E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,qEAAqE;IACrE,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,gBAAgB,GAAG,YAAY,CAAC,QAAQ,EAAE,KAAK,QAAQ,CAAC;IAE9D,IAAI,gBAAgB,EAAE,CAAC;QACrB,MAAM,YAAY,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;QACzD,WAAW,IAAI,YAAY,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC5B,CAAC;IAED,mDAAmD;IACnD,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1E,MAAM,cAAc,GAAkB,EAAE,CAAC;IAEzC,KAAK,IAAI,CAAC,GAAG,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACvD,MAAM,GAAG,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,SAAS,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAE7C,IAAI,WAAW,GAAG,SAAS,GAAG,eAAe,EAAE,CAAC;YAC9C,4BAA4B;YAC5B,MAAM;QACR,CAAC;QAED,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,WAAW,IAAI,SAAS,CAAC;IAC3B,CAAC;IAED,uDAAuD;IACvD,OAAO,gBAAgB,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitizes objects for inclusion in chat debug meta.
|
|
3
|
+
* Strips embeddings, truncates long strings, and handles circular refs.
|
|
4
|
+
*/
|
|
5
|
+
/** Exported for tests that assert on circular-ref placeholder. */
|
|
6
|
+
export declare const SANITIZATION_ERROR_PLACEHOLDER = "[sanitization error]";
|
|
7
|
+
/**
|
|
8
|
+
* Sanitizes an object for safe inclusion in debug meta.
|
|
9
|
+
* - Replaces embedding/vector keys and long number arrays with placeholders.
|
|
10
|
+
* - Truncates strings over maxStringLength.
|
|
11
|
+
* - On circular reference or error, returns a placeholder string.
|
|
12
|
+
*
|
|
13
|
+
* @param obj - Value to sanitize (object, array, or primitive)
|
|
14
|
+
* @param maxStringLength - Max string length before truncation (default 2048)
|
|
15
|
+
* @returns Sanitized copy or "[sanitization error]" on failure
|
|
16
|
+
*/
|
|
17
|
+
export declare function sanitizeForDebugMeta(obj: unknown, maxStringLength?: number): unknown;
|
|
18
|
+
//# sourceMappingURL=debug-meta.sanitizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-meta.sanitizer.d.ts","sourceRoot":"","sources":["../../src/support/debug-meta.sanitizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,kEAAkE;AAClE,eAAO,MAAM,8BAA8B,yBAAyB,CAAC;AAwDrE;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,OAAO,EACZ,eAAe,GAAE,MAAkC,GAClD,OAAO,CAOT"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitizes objects for inclusion in chat debug meta.
|
|
3
|
+
* Strips embeddings, truncates long strings, and handles circular refs.
|
|
4
|
+
*/
|
|
5
|
+
const BLOCKLIST_KEYS = new Set([
|
|
6
|
+
"embedding",
|
|
7
|
+
"embeddingVector",
|
|
8
|
+
"vector",
|
|
9
|
+
]);
|
|
10
|
+
const BLOCKLIST_SUFFIXES = ["Embedding", "Vector"];
|
|
11
|
+
const EMBEDDING_ARRAY_THRESHOLD = 100;
|
|
12
|
+
const DEFAULT_MAX_STRING_LENGTH = 2048;
|
|
13
|
+
/** Exported for tests that assert on circular-ref placeholder. */
|
|
14
|
+
export const SANITIZATION_ERROR_PLACEHOLDER = "[sanitization error]";
|
|
15
|
+
function isBlocklistedKey(key) {
|
|
16
|
+
if (BLOCKLIST_KEYS.has(key))
|
|
17
|
+
return true;
|
|
18
|
+
return BLOCKLIST_SUFFIXES.some((s) => key.endsWith(s));
|
|
19
|
+
}
|
|
20
|
+
function isNumberArray(arr) {
|
|
21
|
+
return Array.isArray(arr) && arr.length > 0 && typeof arr[0] === "number";
|
|
22
|
+
}
|
|
23
|
+
function truncateString(str, maxLen) {
|
|
24
|
+
if (str.length <= maxLen)
|
|
25
|
+
return str;
|
|
26
|
+
return `[truncated, ${str.length} chars]`;
|
|
27
|
+
}
|
|
28
|
+
function sanitizeValue(value, maxStringLength, seen) {
|
|
29
|
+
if (value === null || value === undefined)
|
|
30
|
+
return value;
|
|
31
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
32
|
+
return value;
|
|
33
|
+
if (typeof value === "string")
|
|
34
|
+
return truncateString(value, maxStringLength);
|
|
35
|
+
if (typeof value === "object") {
|
|
36
|
+
if (seen.has(value))
|
|
37
|
+
return SANITIZATION_ERROR_PLACEHOLDER;
|
|
38
|
+
seen.add(value);
|
|
39
|
+
if (Array.isArray(value)) {
|
|
40
|
+
if (isNumberArray(value) && value.length > EMBEDDING_ARRAY_THRESHOLD)
|
|
41
|
+
return `[embedding, length ${value.length}]`;
|
|
42
|
+
return value.map((item) => sanitizeValue(item, maxStringLength, seen));
|
|
43
|
+
}
|
|
44
|
+
const obj = value;
|
|
45
|
+
const out = {};
|
|
46
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
47
|
+
if (isBlocklistedKey(k)) {
|
|
48
|
+
if (Array.isArray(v) && isNumberArray(v))
|
|
49
|
+
out[k] = `[embedding, length ${v.length}]`;
|
|
50
|
+
else if (Array.isArray(v))
|
|
51
|
+
out[k] = `[array, length ${v.length}]`;
|
|
52
|
+
else
|
|
53
|
+
out[k] = "[redacted]";
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
out[k] = sanitizeValue(v, maxStringLength, seen);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Sanitizes an object for safe inclusion in debug meta.
|
|
65
|
+
* - Replaces embedding/vector keys and long number arrays with placeholders.
|
|
66
|
+
* - Truncates strings over maxStringLength.
|
|
67
|
+
* - On circular reference or error, returns a placeholder string.
|
|
68
|
+
*
|
|
69
|
+
* @param obj - Value to sanitize (object, array, or primitive)
|
|
70
|
+
* @param maxStringLength - Max string length before truncation (default 2048)
|
|
71
|
+
* @returns Sanitized copy or "[sanitization error]" on failure
|
|
72
|
+
*/
|
|
73
|
+
export function sanitizeForDebugMeta(obj, maxStringLength = DEFAULT_MAX_STRING_LENGTH) {
|
|
74
|
+
try {
|
|
75
|
+
const seen = new WeakSet();
|
|
76
|
+
return sanitizeValue(obj, maxStringLength, seen);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return SANITIZATION_ERROR_PLACEHOLDER;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=debug-meta.sanitizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-meta.sanitizer.js","sourceRoot":"","sources":["../../src/support/debug-meta.sanitizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Input for computing feed health score. */
|
|
2
|
+
export interface FeedHealthInput {
|
|
3
|
+
connectionCount: number;
|
|
4
|
+
connectorFlowCount: number;
|
|
5
|
+
expiredCount: number;
|
|
6
|
+
totalActionable: number;
|
|
7
|
+
/** Unix ms timestamp of last rediscovery, or null if never. */
|
|
8
|
+
lastRediscoveryAt: number | null;
|
|
9
|
+
/** Window in ms over which freshness decays from 1 → 0 (e.g. 12h). */
|
|
10
|
+
freshnessWindowMs: number;
|
|
11
|
+
/** Score threshold below which shouldMaintain is true. Default 0.5. */
|
|
12
|
+
threshold?: number;
|
|
13
|
+
}
|
|
14
|
+
/** Output of feed health computation. */
|
|
15
|
+
export interface FeedHealthResult {
|
|
16
|
+
score: number;
|
|
17
|
+
breakdown: {
|
|
18
|
+
composition: number;
|
|
19
|
+
freshness: number;
|
|
20
|
+
expirationRatio: number;
|
|
21
|
+
};
|
|
22
|
+
shouldMaintain: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Compute feed health score (0–1) from current feed state.
|
|
26
|
+
* Pure function, no side effects.
|
|
27
|
+
*
|
|
28
|
+
* @param input - Current feed composition and timing data
|
|
29
|
+
* @returns Health score with breakdown and maintenance recommendation
|
|
30
|
+
*/
|
|
31
|
+
export declare function computeFeedHealth(input: FeedHealthInput): FeedHealthResult;
|
|
32
|
+
//# sourceMappingURL=feed.health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feed.health.d.ts","sourceRoot":"","sources":["../../src/support/feed.health.ts"],"names":[],"mappings":"AAEA,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,sEAAsE;IACtE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,yCAAyC;AACzC,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE;QACT,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,cAAc,EAAE,OAAO,CAAC;CACzB;AAiDD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAkC1E"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { FEED_SOFT_TARGETS } from './opportunity.utils.js';
|
|
2
|
+
const WEIGHT_COMPOSITION = 0.4;
|
|
3
|
+
const WEIGHT_FRESHNESS = 0.3;
|
|
4
|
+
const WEIGHT_EXPIRATION = 0.3;
|
|
5
|
+
const DEFAULT_THRESHOLD = 0.5;
|
|
6
|
+
/**
|
|
7
|
+
* Compute composition sub-score: how close current counts are to soft targets.
|
|
8
|
+
* Uses normalized distance: 1 - (|actual - target| / max(target, actual, 1)) per category,
|
|
9
|
+
* then averages across categories.
|
|
10
|
+
*/
|
|
11
|
+
function scoreComposition(connectionCount, connectorFlowCount, expiredCount) {
|
|
12
|
+
const categories = [
|
|
13
|
+
{ actual: connectionCount, target: FEED_SOFT_TARGETS.connection },
|
|
14
|
+
{ actual: connectorFlowCount, target: FEED_SOFT_TARGETS.connectorFlow },
|
|
15
|
+
{ actual: expiredCount, target: FEED_SOFT_TARGETS.expired },
|
|
16
|
+
];
|
|
17
|
+
let totalScore = 0;
|
|
18
|
+
for (const { actual, target } of categories) {
|
|
19
|
+
const diff = Math.abs(actual - target);
|
|
20
|
+
const denom = Math.max(target, actual, 1);
|
|
21
|
+
totalScore += 1 - diff / denom;
|
|
22
|
+
}
|
|
23
|
+
return totalScore / categories.length;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Compute freshness sub-score: linear decay from 1 → 0 over freshnessWindowMs.
|
|
27
|
+
*/
|
|
28
|
+
function scoreFreshness(lastRediscoveryAt, freshnessWindowMs) {
|
|
29
|
+
if (lastRediscoveryAt == null)
|
|
30
|
+
return 0;
|
|
31
|
+
const elapsed = Date.now() - lastRediscoveryAt;
|
|
32
|
+
if (elapsed <= 0)
|
|
33
|
+
return 1;
|
|
34
|
+
if (elapsed >= freshnessWindowMs)
|
|
35
|
+
return 0;
|
|
36
|
+
return 1 - elapsed / freshnessWindowMs;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Compute expiration ratio sub-score: 1 - (expired / total).
|
|
40
|
+
*/
|
|
41
|
+
function scoreExpirationRatio(expiredCount, totalActionable) {
|
|
42
|
+
const total = totalActionable + expiredCount;
|
|
43
|
+
if (total === 0)
|
|
44
|
+
return 0;
|
|
45
|
+
return 1 - expiredCount / total;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Compute feed health score (0–1) from current feed state.
|
|
49
|
+
* Pure function, no side effects.
|
|
50
|
+
*
|
|
51
|
+
* @param input - Current feed composition and timing data
|
|
52
|
+
* @returns Health score with breakdown and maintenance recommendation
|
|
53
|
+
*/
|
|
54
|
+
export function computeFeedHealth(input) {
|
|
55
|
+
const { connectionCount, connectorFlowCount, expiredCount, totalActionable, lastRediscoveryAt, freshnessWindowMs, threshold = DEFAULT_THRESHOLD, } = input;
|
|
56
|
+
// Empty feed is always unhealthy
|
|
57
|
+
if (totalActionable === 0 && expiredCount === 0) {
|
|
58
|
+
return {
|
|
59
|
+
score: 0,
|
|
60
|
+
breakdown: { composition: 0, freshness: 0, expirationRatio: 0 },
|
|
61
|
+
shouldMaintain: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const composition = scoreComposition(connectionCount, connectorFlowCount, expiredCount);
|
|
65
|
+
const freshness = scoreFreshness(lastRediscoveryAt, freshnessWindowMs);
|
|
66
|
+
const expirationRatio = scoreExpirationRatio(expiredCount, totalActionable);
|
|
67
|
+
const score = WEIGHT_COMPOSITION * composition +
|
|
68
|
+
WEIGHT_FRESHNESS * freshness +
|
|
69
|
+
WEIGHT_EXPIRATION * expirationRatio;
|
|
70
|
+
return {
|
|
71
|
+
score,
|
|
72
|
+
breakdown: { composition, freshness, expirationRatio },
|
|
73
|
+
shouldMaintain: score < threshold,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=feed.health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feed.health.js","sourceRoot":"","sources":["../../src/support/feed.health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AA2B3D,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAC/B,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAC9B,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,eAAuB,EAAE,kBAA0B,EAAE,YAAoB;IACjG,MAAM,UAAU,GAAG;QACjB,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,iBAAiB,CAAC,UAAU,EAAE;QACjE,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,iBAAiB,CAAC,aAAa,EAAE;QACvE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,iBAAiB,CAAC,OAAO,EAAE;KAC5D,CAAC;IAEF,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC1C,UAAU,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC;IACjC,CAAC;IAED,OAAO,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,iBAAgC,EAAE,iBAAyB;IACjF,IAAI,iBAAiB,IAAI,IAAI;QAAE,OAAO,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,iBAAiB,CAAC;IAC/C,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAC3B,IAAI,OAAO,IAAI,iBAAiB;QAAE,OAAO,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,OAAO,GAAG,iBAAiB,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAAC,YAAoB,EAAE,eAAuB;IACzE,MAAM,KAAK,GAAG,eAAe,GAAG,YAAY,CAAC;IAC7C,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1B,OAAO,CAAC,GAAG,YAAY,GAAG,KAAK,CAAC;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAsB;IACtD,MAAM,EACJ,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,SAAS,GAAG,iBAAiB,GAC9B,GAAG,KAAK,CAAC;IAEV,iCAAiC;IACjC,IAAI,eAAe,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO;YACL,KAAK,EAAE,CAAC;YACR,SAAS,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE;YAC/D,cAAc,EAAE,IAAI;SACrB,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,gBAAgB,CAAC,eAAe,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAC;IACxF,MAAM,SAAS,GAAG,cAAc,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;IACvE,MAAM,eAAe,GAAG,oBAAoB,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;IAE5E,MAAM,KAAK,GACT,kBAAkB,GAAG,WAAW;QAChC,gBAAgB,GAAG,SAAS;QAC5B,iBAAiB,GAAG,eAAe,CAAC;IAEtC,OAAO;QACL,KAAK;QACL,SAAS,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE;QACtD,cAAc,EAAE,KAAK,GAAG,SAAS;KAClC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Introducer Discovery: proactive discovery of connector-flow opportunities
|
|
3
|
+
* between a user's contacts.
|
|
4
|
+
*
|
|
5
|
+
* Selects top-N contacts from the user's personal index and runs scoped
|
|
6
|
+
* HyDE discovery for each, creating latent introducer opportunities that
|
|
7
|
+
* the user (as introducer) must approve before parties see them.
|
|
8
|
+
*/
|
|
9
|
+
/** Maximum contacts to evaluate per maintenance cycle. */
|
|
10
|
+
export declare const MAX_CONTACTS_PER_CYCLE = 5;
|
|
11
|
+
/** Maximum candidate opportunities per contact. */
|
|
12
|
+
export declare const MAX_CANDIDATES_PER_CONTACT = 3;
|
|
13
|
+
/** Detection source value for introducer-discovered opportunities. */
|
|
14
|
+
export declare const INTRODUCER_DISCOVERY_SOURCE: "introducer_discovery";
|
|
15
|
+
/** A contact with their active intents, used for introducer discovery selection. */
|
|
16
|
+
export interface ContactWithIntents {
|
|
17
|
+
userId: string;
|
|
18
|
+
/** Most recent intent updatedAt timestamp (ISO string or null). */
|
|
19
|
+
latestIntentAt: string | null;
|
|
20
|
+
/** Number of active intents this contact has. */
|
|
21
|
+
intentCount: number;
|
|
22
|
+
}
|
|
23
|
+
/** Database methods needed for introducer discovery contact selection. */
|
|
24
|
+
export interface IntroducerDiscoveryDatabase {
|
|
25
|
+
/** Get the user's personal index ID. */
|
|
26
|
+
getPersonalIndexId(userId: string): Promise<string | null>;
|
|
27
|
+
/** Get contacts from a personal index with their intent freshness data. */
|
|
28
|
+
getContactsWithIntentFreshness(personalIndexId: string, ownerId: string, limit: number): Promise<ContactWithIntents[]>;
|
|
29
|
+
}
|
|
30
|
+
/** Queue interface for enqueuing introducer discovery jobs. */
|
|
31
|
+
export interface IntroducerDiscoveryQueue {
|
|
32
|
+
addJob(data: {
|
|
33
|
+
intentId: string;
|
|
34
|
+
userId: string;
|
|
35
|
+
indexIds?: string[];
|
|
36
|
+
contactUserId?: string;
|
|
37
|
+
}, options?: {
|
|
38
|
+
priority?: number;
|
|
39
|
+
jobId?: string;
|
|
40
|
+
}): Promise<unknown>;
|
|
41
|
+
}
|
|
42
|
+
/** Result of a single introducer discovery cycle. */
|
|
43
|
+
export interface IntroducerDiscoveryResult {
|
|
44
|
+
contactsEvaluated: number;
|
|
45
|
+
jobsEnqueued: number;
|
|
46
|
+
skippedReason?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Select top-N contacts for introducer discovery, sorted by intent freshness.
|
|
50
|
+
* Contacts with no active intents are excluded.
|
|
51
|
+
*
|
|
52
|
+
* @param database - Database adapter with contact/intent queries
|
|
53
|
+
* @param userId - The introducer user
|
|
54
|
+
* @param limit - Max contacts to return (default MAX_CONTACTS_PER_CYCLE)
|
|
55
|
+
* @returns Sorted contacts with intent data
|
|
56
|
+
*/
|
|
57
|
+
export declare function selectContactsForDiscovery(database: IntroducerDiscoveryDatabase, userId: string, limit?: number): Promise<ContactWithIntents[]>;
|
|
58
|
+
/**
|
|
59
|
+
* Determine whether introducer discovery should run based on the current
|
|
60
|
+
* connector-flow composition. Triggers when connector-flow count is below
|
|
61
|
+
* the soft target.
|
|
62
|
+
*
|
|
63
|
+
* @param connectorFlowCount - Current number of connector-flow opportunities
|
|
64
|
+
* @param connectorFlowTarget - Soft target (default 2)
|
|
65
|
+
* @returns Whether introducer discovery should run
|
|
66
|
+
*/
|
|
67
|
+
export declare function shouldRunIntroducerDiscovery(connectorFlowCount: number, connectorFlowTarget?: number): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Run introducer discovery for a user: select contacts, enqueue discovery jobs.
|
|
70
|
+
* Each job uses onBehalfOfUserId so the opportunity graph treats the user as introducer.
|
|
71
|
+
*
|
|
72
|
+
* @param database - Database adapter for contact queries
|
|
73
|
+
* @param queue - Queue for enqueuing discovery jobs
|
|
74
|
+
* @param userId - The introducer user
|
|
75
|
+
* @returns Summary of the discovery cycle
|
|
76
|
+
*/
|
|
77
|
+
export declare function runIntroducerDiscovery(database: IntroducerDiscoveryDatabase, queue: IntroducerDiscoveryQueue, userId: string): Promise<IntroducerDiscoveryResult>;
|
|
78
|
+
//# sourceMappingURL=introducer.discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introducer.discovery.d.ts","sourceRoot":"","sources":["../../src/support/introducer.discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,0DAA0D;AAC1D,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,mDAAmD;AACnD,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C,sEAAsE;AACtE,eAAO,MAAM,2BAA2B,EAAG,sBAA+B,CAAC;AAE3E,oFAAoF;AACpF,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,0EAA0E;AAC1E,MAAM,WAAW,2BAA2B;IAC1C,wCAAwC;IACxC,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3D,2EAA2E;IAC3E,8BAA8B,CAC5B,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;CAClC;AAED,+DAA+D;AAC/D,MAAM,WAAW,wBAAwB;IACvC,MAAM,CACJ,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,EACvF,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC9C,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AAED,qDAAqD;AACrD,MAAM,WAAW,yBAAyB;IACxC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,2BAA2B,EACrC,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAA+B,GACrC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAgB/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,kBAAkB,EAAE,MAAM,EAC1B,mBAAmB,GAAE,MAAU,GAC9B,OAAO,CAET;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,2BAA2B,EACrC,KAAK,EAAE,wBAAwB,EAC/B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,yBAAyB,CAAC,CAqDpC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Introducer Discovery: proactive discovery of connector-flow opportunities
|
|
3
|
+
* between a user's contacts.
|
|
4
|
+
*
|
|
5
|
+
* Selects top-N contacts from the user's personal index and runs scoped
|
|
6
|
+
* HyDE discovery for each, creating latent introducer opportunities that
|
|
7
|
+
* the user (as introducer) must approve before parties see them.
|
|
8
|
+
*/
|
|
9
|
+
import { protocolLogger } from './protocol.logger.js';
|
|
10
|
+
const logger = protocolLogger('IntroducerDiscovery');
|
|
11
|
+
/** Maximum contacts to evaluate per maintenance cycle. */
|
|
12
|
+
export const MAX_CONTACTS_PER_CYCLE = 5;
|
|
13
|
+
/** Maximum candidate opportunities per contact. */
|
|
14
|
+
export const MAX_CANDIDATES_PER_CONTACT = 3;
|
|
15
|
+
/** Detection source value for introducer-discovered opportunities. */
|
|
16
|
+
export const INTRODUCER_DISCOVERY_SOURCE = 'introducer_discovery';
|
|
17
|
+
/**
|
|
18
|
+
* Select top-N contacts for introducer discovery, sorted by intent freshness.
|
|
19
|
+
* Contacts with no active intents are excluded.
|
|
20
|
+
*
|
|
21
|
+
* @param database - Database adapter with contact/intent queries
|
|
22
|
+
* @param userId - The introducer user
|
|
23
|
+
* @param limit - Max contacts to return (default MAX_CONTACTS_PER_CYCLE)
|
|
24
|
+
* @returns Sorted contacts with intent data
|
|
25
|
+
*/
|
|
26
|
+
export async function selectContactsForDiscovery(database, userId, limit = MAX_CONTACTS_PER_CYCLE) {
|
|
27
|
+
const personalIndexId = await database.getPersonalIndexId(userId);
|
|
28
|
+
if (!personalIndexId) {
|
|
29
|
+
logger.verbose(`[IntroducerDiscovery] No personal index found — userId=${userId}`);
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const contacts = await database.getContactsWithIntentFreshness(personalIndexId, userId, limit);
|
|
33
|
+
logger.verbose(`[IntroducerDiscovery] Selected contacts for discovery — userId=${userId} totalContacts=${contacts.length} limit=${limit}`);
|
|
34
|
+
return contacts;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Determine whether introducer discovery should run based on the current
|
|
38
|
+
* connector-flow composition. Triggers when connector-flow count is below
|
|
39
|
+
* the soft target.
|
|
40
|
+
*
|
|
41
|
+
* @param connectorFlowCount - Current number of connector-flow opportunities
|
|
42
|
+
* @param connectorFlowTarget - Soft target (default 2)
|
|
43
|
+
* @returns Whether introducer discovery should run
|
|
44
|
+
*/
|
|
45
|
+
export function shouldRunIntroducerDiscovery(connectorFlowCount, connectorFlowTarget = 2) {
|
|
46
|
+
return connectorFlowCount < connectorFlowTarget;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Run introducer discovery for a user: select contacts, enqueue discovery jobs.
|
|
50
|
+
* Each job uses onBehalfOfUserId so the opportunity graph treats the user as introducer.
|
|
51
|
+
*
|
|
52
|
+
* @param database - Database adapter for contact queries
|
|
53
|
+
* @param queue - Queue for enqueuing discovery jobs
|
|
54
|
+
* @param userId - The introducer user
|
|
55
|
+
* @returns Summary of the discovery cycle
|
|
56
|
+
*/
|
|
57
|
+
export async function runIntroducerDiscovery(database, queue, userId) {
|
|
58
|
+
const personalIndexId = await database.getPersonalIndexId(userId);
|
|
59
|
+
if (!personalIndexId) {
|
|
60
|
+
return { contactsEvaluated: 0, jobsEnqueued: 0, skippedReason: 'no_personal_index' };
|
|
61
|
+
}
|
|
62
|
+
const contacts = await selectContactsForDiscovery(database, userId);
|
|
63
|
+
if (contacts.length === 0) {
|
|
64
|
+
return { contactsEvaluated: 0, jobsEnqueued: 0, skippedReason: 'no_contacts' };
|
|
65
|
+
}
|
|
66
|
+
const bucket = Math.floor(Date.now() / (12 * 60 * 60 * 1000)); // 12h dedup bucket
|
|
67
|
+
let jobsEnqueued = 0;
|
|
68
|
+
const results = await Promise.allSettled(contacts.map(async (contact) => {
|
|
69
|
+
// For each contact, we enqueue a discovery job using one of their intents
|
|
70
|
+
// The opportunity graph will use onBehalfOfUserId to discover on behalf of the contact
|
|
71
|
+
// while the userId (introducer) gets the introducer role
|
|
72
|
+
const jobId = `introducer-discovery-${userId}-${contact.userId}-${bucket}`;
|
|
73
|
+
try {
|
|
74
|
+
await queue.addJob({
|
|
75
|
+
intentId: `introducer:${contact.userId}`,
|
|
76
|
+
userId,
|
|
77
|
+
indexIds: [personalIndexId],
|
|
78
|
+
contactUserId: contact.userId,
|
|
79
|
+
}, { priority: 15, jobId });
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
84
|
+
if (/duplicate|already exists|job.*id/i.test(message)) {
|
|
85
|
+
logger.verbose(`[IntroducerDiscovery] Job skipped (duplicate) — userId=${userId} contactUserId=${contact.userId} error=${message}`);
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
throw err;
|
|
89
|
+
}
|
|
90
|
+
}));
|
|
91
|
+
for (const r of results) {
|
|
92
|
+
if (r.status === 'rejected') {
|
|
93
|
+
const errMsg = r.reason instanceof Error ? r.reason.message : String(r.reason);
|
|
94
|
+
logger.error(`[IntroducerDiscovery] Job enqueue failed: ${errMsg}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
jobsEnqueued = results.filter((r) => r.status === 'fulfilled' && r.value).length;
|
|
98
|
+
logger.info(`[IntroducerDiscovery] Discovery cycle complete — userId=${userId} contactsEvaluated=${contacts.length} jobsEnqueued=${jobsEnqueued}`);
|
|
99
|
+
return { contactsEvaluated: contacts.length, jobsEnqueued };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=introducer.discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introducer.discovery.js","sourceRoot":"","sources":["../../src/support/introducer.discovery.ts"],"names":[],"mappings":"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"}
|