@indexnetwork/protocol 4.5.0-rc.323.1 → 4.5.0-rc.325.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/dist/agent/agent.tools.js +1 -1
  2. package/dist/agent/agent.tools.js.map +1 -1
  3. package/dist/chat/chat.interrupt.classifier.js +1 -1
  4. package/dist/chat/chat.interrupt.classifier.js.map +1 -1
  5. package/dist/chat/chat.suggester.js +3 -3
  6. package/dist/chat/chat.suggester.js.map +1 -1
  7. package/dist/chat/chat.title.generator.js +2 -2
  8. package/dist/chat/chat.title.generator.js.map +1 -1
  9. package/dist/contact/contact.tools.js +1 -1
  10. package/dist/contact/contact.tools.js.map +1 -1
  11. package/dist/enrichment/enrichment.graph.d.ts.map +1 -1
  12. package/dist/enrichment/enrichment.graph.js +9 -3
  13. package/dist/enrichment/enrichment.graph.js.map +1 -1
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/integration/integration.tools.js +1 -1
  19. package/dist/integration/integration.tools.js.map +1 -1
  20. package/dist/intent/intent.graph.d.ts.map +1 -1
  21. package/dist/intent/intent.graph.js +12 -10
  22. package/dist/intent/intent.graph.js.map +1 -1
  23. package/dist/intent/intent.indexer.d.ts.map +1 -1
  24. package/dist/intent/intent.indexer.js +4 -3
  25. package/dist/intent/intent.indexer.js.map +1 -1
  26. package/dist/intent/intent.inferrer.d.ts.map +1 -1
  27. package/dist/intent/intent.inferrer.js +2 -1
  28. package/dist/intent/intent.inferrer.js.map +1 -1
  29. package/dist/intent/intent.reconciler.d.ts.map +1 -1
  30. package/dist/intent/intent.reconciler.js +5 -4
  31. package/dist/intent/intent.reconciler.js.map +1 -1
  32. package/dist/intent/intent.verifier.d.ts.map +1 -1
  33. package/dist/intent/intent.verifier.js +4 -3
  34. package/dist/intent/intent.verifier.js.map +1 -1
  35. package/dist/maintenance/maintenance.graph.d.ts.map +1 -1
  36. package/dist/maintenance/maintenance.graph.js +27 -5
  37. package/dist/maintenance/maintenance.graph.js.map +1 -1
  38. package/dist/mcp/mcp.server.d.ts.map +1 -1
  39. package/dist/mcp/mcp.server.js +5 -4
  40. package/dist/mcp/mcp.server.js.map +1 -1
  41. package/dist/negotiation/insight.generator.js +2 -2
  42. package/dist/negotiation/insight.generator.js.map +1 -1
  43. package/dist/negotiation/negotiation.graph.d.ts.map +1 -1
  44. package/dist/negotiation/negotiation.graph.js +15 -11
  45. package/dist/negotiation/negotiation.graph.js.map +1 -1
  46. package/dist/negotiation/negotiation.tools.js +1 -1
  47. package/dist/negotiation/negotiation.tools.js.map +1 -1
  48. package/dist/network/network.recommender.d.ts.map +1 -1
  49. package/dist/network/network.recommender.js +5 -4
  50. package/dist/network/network.recommender.js.map +1 -1
  51. package/dist/network/network.tools.d.ts.map +1 -1
  52. package/dist/network/network.tools.js +4 -2
  53. package/dist/network/network.tools.js.map +1 -1
  54. package/dist/opportunity/feed/feed.graph.d.ts +17 -1
  55. package/dist/opportunity/feed/feed.graph.d.ts.map +1 -1
  56. package/dist/opportunity/feed/feed.graph.js +131 -27
  57. package/dist/opportunity/feed/feed.graph.js.map +1 -1
  58. package/dist/opportunity/feed/feed.state.d.ts +16 -0
  59. package/dist/opportunity/feed/feed.state.d.ts.map +1 -1
  60. package/dist/opportunity/feed/feed.state.js +10 -0
  61. package/dist/opportunity/feed/feed.state.js.map +1 -1
  62. package/dist/opportunity/opportunity.discover.d.ts +1 -1
  63. package/dist/opportunity/opportunity.discover.d.ts.map +1 -1
  64. package/dist/opportunity/opportunity.discover.js +12 -19
  65. package/dist/opportunity/opportunity.discover.js.map +1 -1
  66. package/dist/opportunity/opportunity.enricher.js +2 -2
  67. package/dist/opportunity/opportunity.enricher.js.map +1 -1
  68. package/dist/opportunity/opportunity.evaluator.d.ts.map +1 -1
  69. package/dist/opportunity/opportunity.evaluator.js +9 -7
  70. package/dist/opportunity/opportunity.evaluator.js.map +1 -1
  71. package/dist/opportunity/opportunity.graph.d.ts.map +1 -1
  72. package/dist/opportunity/opportunity.graph.js +123 -105
  73. package/dist/opportunity/opportunity.graph.js.map +1 -1
  74. package/dist/opportunity/opportunity.introducer.js +5 -5
  75. package/dist/opportunity/opportunity.introducer.js.map +1 -1
  76. package/dist/opportunity/opportunity.persist.js +2 -2
  77. package/dist/opportunity/opportunity.persist.js.map +1 -1
  78. package/dist/opportunity/opportunity.presenter.d.ts.map +1 -1
  79. package/dist/opportunity/opportunity.presenter.js +4 -2
  80. package/dist/opportunity/opportunity.presenter.js.map +1 -1
  81. package/dist/opportunity/opportunity.tools.d.ts.map +1 -1
  82. package/dist/opportunity/opportunity.tools.js +7 -5
  83. package/dist/opportunity/opportunity.tools.js.map +1 -1
  84. package/dist/opportunity/opportunity.utils.d.ts +4 -1
  85. package/dist/opportunity/opportunity.utils.d.ts.map +1 -1
  86. package/dist/opportunity/opportunity.utils.js +42 -11
  87. package/dist/opportunity/opportunity.utils.js.map +1 -1
  88. package/dist/premise/premise.analyzer.d.ts.map +1 -1
  89. package/dist/premise/premise.analyzer.js +3 -2
  90. package/dist/premise/premise.analyzer.js.map +1 -1
  91. package/dist/premise/premise.decomposer.d.ts.map +1 -1
  92. package/dist/premise/premise.decomposer.js +12 -3
  93. package/dist/premise/premise.decomposer.js.map +1 -1
  94. package/dist/premise/premise.graph.d.ts.map +1 -1
  95. package/dist/premise/premise.graph.js +19 -9
  96. package/dist/premise/premise.graph.js.map +1 -1
  97. package/dist/premise/premise.indexer.d.ts.map +1 -1
  98. package/dist/premise/premise.indexer.js +2 -1
  99. package/dist/premise/premise.indexer.js.map +1 -1
  100. package/dist/premise/premise.tools.d.ts.map +1 -1
  101. package/dist/premise/premise.tools.js +8 -4
  102. package/dist/premise/premise.tools.js.map +1 -1
  103. package/dist/questioner/questioner.ask.tool.d.ts.map +1 -1
  104. package/dist/questioner/questioner.ask.tool.js +2 -10
  105. package/dist/questioner/questioner.ask.tool.js.map +1 -1
  106. package/dist/questioner/questioner.env.d.ts +50 -0
  107. package/dist/questioner/questioner.env.d.ts.map +1 -0
  108. package/dist/questioner/questioner.env.js +76 -0
  109. package/dist/questioner/questioner.env.js.map +1 -0
  110. package/dist/questioner/questioner.types.d.ts +7 -0
  111. package/dist/questioner/questioner.types.d.ts.map +1 -1
  112. package/dist/questioner/questioner.types.js.map +1 -1
  113. package/dist/shared/agent/tool.factory.d.ts.map +1 -1
  114. package/dist/shared/agent/tool.factory.js +4 -2
  115. package/dist/shared/agent/tool.factory.js.map +1 -1
  116. package/dist/shared/agent/tool.registry.d.ts.map +1 -1
  117. package/dist/shared/agent/tool.registry.js +6 -4
  118. package/dist/shared/agent/tool.registry.js.map +1 -1
  119. package/dist/shared/agent/tool.runtime.js +1 -1
  120. package/dist/shared/agent/tool.runtime.js.map +1 -1
  121. package/dist/shared/interfaces/database.interface.d.ts +1 -1
  122. package/dist/shared/interfaces/database.interface.js.map +1 -1
  123. package/dist/shared/observability/log.d.ts +3 -2
  124. package/dist/shared/observability/log.d.ts.map +1 -1
  125. package/dist/shared/observability/log.js +72 -9
  126. package/dist/shared/observability/log.js.map +1 -1
  127. package/dist/shared/observability/protocol.logger.d.ts.map +1 -1
  128. package/dist/shared/observability/protocol.logger.js +5 -3
  129. package/dist/shared/observability/protocol.logger.js.map +1 -1
  130. package/package.json +1 -1
@@ -8,6 +8,12 @@ import { scopeFromNetworkId } from "../shared/agent/tool.scope.js";
8
8
  import { protocolLogger } from "../shared/observability/protocol.logger.js";
9
9
  import { timed } from "../shared/observability/performance.js";
10
10
  const logger = protocolLogger("PremiseGraphFactory");
11
+ const queryLog = protocolLogger("PremiseGraph:query");
12
+ const analyzeLog = protocolLogger("PremiseGraph:analyze");
13
+ const embedLog = protocolLogger("PremiseGraph:embed");
14
+ const persistLog = protocolLogger("PremiseGraph:persist");
15
+ const indexLog = protocolLogger("PremiseGraph:index");
16
+ const dedupeLog = protocolLogger("PremiseGraph:dedupe");
11
17
  /**
12
18
  * Minimum cosine similarity (0-1) at which a freshly-decomposed premise is treated
13
19
  * as a near-duplicate of an existing ACTIVE premise for the same user and skipped
@@ -53,7 +59,7 @@ export class PremiseGraphFactory {
53
59
  const indexer = this.premiseIndexer;
54
60
  const queryNode = async (state) => {
55
61
  return timed("PremiseGraph.query", async () => {
56
- logger.verbose(`[PremiseGraph.query] Fetching premises for user ${state.userId}`);
62
+ queryLog.verbose('Fetching premises for user', { userId: state.userId });
57
63
  const premises = await this.database.getPremisesForUser(state.userId, 'ACTIVE');
58
64
  return {
59
65
  readResult: {
@@ -68,7 +74,7 @@ export class PremiseGraphFactory {
68
74
  if (!state.assertionText) {
69
75
  return { error: "assertionText is required for create/update mode" };
70
76
  }
71
- logger.verbose(`[PremiseGraph.analyze] Analyzing: "${state.assertionText.substring(0, 50)}..."`);
77
+ analyzeLog.verbose('Analyzing assertion text', { preview: state.assertionText.substring(0, 50) });
72
78
  const start = Date.now();
73
79
  const result = await analyzer.invoke(state.assertionText);
74
80
  const timing = {
@@ -92,7 +98,7 @@ export class PremiseGraphFactory {
92
98
  if (!state.assertionText) {
93
99
  return { error: "assertionText is required for embedding" };
94
100
  }
95
- logger.verbose(`[PremiseGraph.embed] Generating embedding for premise`);
101
+ embedLog.verbose(`Generating embedding for premise`);
96
102
  // Embedder.generate returns number[] | number[][], cast for single string input
97
103
  const embedding = await this.embedder.generate(state.assertionText, undefined, getAbortSignalConfig());
98
104
  return { embedding };
@@ -121,7 +127,11 @@ export class PremiseGraphFactory {
121
127
  threshold: DEDUP_SIMILARITY_THRESHOLD,
122
128
  });
123
129
  if (match) {
124
- logger.verbose(`[PremiseGraph.dedupe] Skipping near-duplicate (similarity=${match.similarity.toFixed(3)} >= ${DEDUP_SIMILARITY_THRESHOLD}) of premise ${match.premiseId}`);
130
+ dedupeLog.verbose('Skipping near-duplicate premise', {
131
+ similarity: Number(match.similarity.toFixed(3)),
132
+ threshold: DEDUP_SIMILARITY_THRESHOLD,
133
+ premiseId: match.premiseId,
134
+ });
125
135
  return { duplicateOf: match };
126
136
  }
127
137
  return {};
@@ -135,7 +145,7 @@ export class PremiseGraphFactory {
135
145
  return { error: "targetPremiseId is required for update mode" };
136
146
  }
137
147
  if (state.operationMode === 'update' && state.targetPremiseId) {
138
- logger.verbose(`[PremiseGraph.persist] Updating premise ${state.targetPremiseId}`);
148
+ persistLog.verbose('Updating premise', { premiseId: state.targetPremiseId });
139
149
  const updated = await this.database.updatePremise(state.targetPremiseId, {
140
150
  assertion: {
141
151
  text: state.assertionText,
@@ -151,7 +161,7 @@ export class PremiseGraphFactory {
151
161
  });
152
162
  return { premise: updated };
153
163
  }
154
- logger.verbose(`[PremiseGraph.persist] Creating new premise for user ${state.userId}`);
164
+ persistLog.verbose('Creating new premise for user', { userId: state.userId });
155
165
  // Provenance confidence: prefer an explicit caller-supplied value; otherwise
156
166
  // derive it from the analyzer's felicity scores (how authoritative, sincere,
157
167
  // and clear the assertion is) rather than a blanket 1.0, so the stored
@@ -184,7 +194,7 @@ export class PremiseGraphFactory {
184
194
  return timed("PremiseGraph.index", async () => {
185
195
  if (!state.premise)
186
196
  return {};
187
- logger.verbose(`[PremiseGraph.index] Scoring premise against user networks`);
197
+ indexLog.verbose(`Scoring premise against user networks`);
188
198
  const assignmentMemberships = await this.database.getAssignmentNetworkMembershipsForUser(state.userId);
189
199
  const requestScope = state.scopeType && state.scopeId
190
200
  ? { scopeType: state.scopeType, scopeId: state.scopeId }
@@ -239,10 +249,10 @@ export class PremiseGraphFactory {
239
249
  }
240
250
  }
241
251
  catch (err) {
242
- logger.verbose(`[PremiseGraph.index] Failed to score network ${networkId}, skipping: ${err}`);
252
+ indexLog.verbose('Failed to score network, skipping', { networkId, error: err });
243
253
  }
244
254
  }
245
- logger.verbose(`[PremiseGraph.index] Assigned to ${assignments.length} networks`);
255
+ indexLog.verbose('Assigned to networks', { count: assignments.length });
246
256
  return { networkAssignments: assignments, agentTimings };
247
257
  });
248
258
  };
@@ -1 +1 @@
1
- {"version":3,"file":"premise.graph.js","sourceRoot":"/","sources":["premise/premise.graph.ts"],"names":[],"mappings":"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","sourcesContent":["import { StateGraph, START, END } from \"@langchain/langgraph\";\n\nimport { PremiseGraphState } from \"./premise.state.js\";\nimport { PremiseAnalyzer } from \"./premise.analyzer.js\";\nimport type { PremiseAnalyzerOutput } from \"./premise.analyzer.js\";\nimport { PremiseIndexer } from \"./premise.indexer.js\";\n\nimport { buildNetworkAssignmentDecision, resolveAssignmentNetworkScope } from \"../shared/assignment/network-assignment.policy.js\";\nimport { getAbortSignalConfig } from \"../shared/agent/model-signal.js\";\nimport { scopeFromNetworkId } from \"../shared/agent/tool.scope.js\";\nimport type { PremiseGraphDatabase, PremiseAnalysis } from \"../shared/interfaces/database.interface.js\";\nimport type { Embedder } from \"../shared/interfaces/embedder.interface.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { timed } from \"../shared/observability/performance.js\";\nimport type { DebugMetaAgent } from \"../chat/chat-streaming.types.js\";\n\nconst logger = protocolLogger(\"PremiseGraphFactory\");\n\n/**\n * Minimum cosine similarity (0-1) at which a freshly-decomposed premise is treated\n * as a near-duplicate of an existing ACTIVE premise for the same user and skipped\n * on create. Tuned high so genuine paraphrases collapse while distinct facts (e.g.\n * \"I work at Google\" vs \"I worked at Google\") still persist. Override with\n * PREMISE_DEDUP_SIMILARITY.\n */\nconst DEDUP_SIMILARITY_THRESHOLD = (() => {\n const raw = Number(process.env.PREMISE_DEDUP_SIMILARITY);\n return Number.isFinite(raw) && raw > 0 && raw <= 1 ? raw : 0.93;\n})();\n\n/**\n * Derive a premise provenance confidence (0-1) from the analyzer's felicity scores.\n * Averages authority, sincerity, and clarity — the dimensions that speak to how\n * trustworthy the self-assertion is. Falls back to 1.0 when no analysis is present.\n */\nfunction deriveProvenanceConfidence(analysis: PremiseAnalysis | undefined): number {\n if (!analysis) return 1.0;\n const { felicityAuthority, felicitySincerity, felicityClarity } = analysis;\n const mean = (felicityAuthority + felicitySincerity + felicityClarity) / 3;\n if (!Number.isFinite(mean)) return 1.0;\n return Math.min(1, Math.max(0, mean));\n}\n\n/**\n * Graph factory for premise lifecycle: create, update, and query modes.\n */\nexport class PremiseGraphFactory {\n constructor(\n private database: PremiseGraphDatabase,\n private embedder: Embedder,\n private premiseIndexer: PremiseIndexer = new PremiseIndexer(),\n private premiseAnalyzer: { invoke(premiseText: string, profileContext?: string): Promise<PremiseAnalyzerOutput> } = new PremiseAnalyzer(),\n ) {}\n\n /**\n * Compiles and returns the premise lifecycle graph.\n *\n * @returns A compiled LangGraph graph handling create, update, and query modes.\n */\n public createGraph() {\n const analyzer = this.premiseAnalyzer;\n const indexer = this.premiseIndexer;\n\n const queryNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.query\", async () => {\n logger.verbose(`[PremiseGraph.query] Fetching premises for user ${state.userId}`);\n const premises = await this.database.getPremisesForUser(state.userId, 'ACTIVE');\n return {\n readResult: {\n premises,\n count: premises.length,\n },\n };\n });\n };\n\n const analyzeNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.analyze\", async () => {\n if (!state.assertionText) {\n return { error: \"assertionText is required for create/update mode\" };\n }\n\n logger.verbose(`[PremiseGraph.analyze] Analyzing: \"${state.assertionText.substring(0, 50)}...\"`);\n\n const start = Date.now();\n const result = await analyzer.invoke(state.assertionText);\n const timing: DebugMetaAgent = {\n name: \"premise-analyzer\",\n durationMs: Date.now() - start,\n };\n\n const analysis: PremiseAnalysis = {\n speechActType: result.speechActType,\n felicityAuthority: result.felicityAuthority,\n felicitySincerity: result.felicitySincerity,\n felicityClarity: result.felicityClarity,\n semanticEntropy: result.semanticEntropy,\n };\n\n return { analysis, agentTimings: [timing] };\n });\n };\n\n const embedNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.embed\", async () => {\n if (state.error) return {};\n\n if (!state.assertionText) {\n return { error: \"assertionText is required for embedding\" };\n }\n\n logger.verbose(`[PremiseGraph.embed] Generating embedding for premise`);\n\n // Embedder.generate returns number[] | number[][], cast for single string input\n const embedding = await this.embedder.generate(state.assertionText, undefined, getAbortSignalConfig()) as number[];\n return { embedding };\n });\n };\n\n // ─────────────────────────────────────────────────────────\n // NODE: Dedupe (create mode only)\n // Skips persisting a near-duplicate of an existing ACTIVE premise for the same\n // user. Re-running similar input (e.g. repeated enrichment) therefore does not\n // accumulate near-identical premises. No-op for update mode, when no embedding\n // is available, or when the adapter does not implement findSimilarActivePremise.\n // ─────────────────────────────────────────────────────────\n const dedupeNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.dedupe\", async () => {\n if (state.error) return {};\n if (state.operationMode === 'update') return {};\n if (!state.embedding || state.embedding.length === 0) return {};\n if (typeof this.database.findSimilarActivePremise !== 'function') return {};\n\n const match = await this.database.findSimilarActivePremise({\n userId: state.userId,\n embedding: state.embedding,\n threshold: DEDUP_SIMILARITY_THRESHOLD,\n });\n\n if (match) {\n logger.verbose(\n `[PremiseGraph.dedupe] Skipping near-duplicate (similarity=${match.similarity.toFixed(3)} >= ${DEDUP_SIMILARITY_THRESHOLD}) of premise ${match.premiseId}`,\n );\n return { duplicateOf: match };\n }\n return {};\n });\n };\n\n const persistNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.persist\", async () => {\n if (state.error) return {};\n\n if (state.operationMode === 'update' && !state.targetPremiseId) {\n return { error: \"targetPremiseId is required for update mode\" };\n }\n\n if (state.operationMode === 'update' && state.targetPremiseId) {\n logger.verbose(`[PremiseGraph.persist] Updating premise ${state.targetPremiseId}`);\n\n const updated = await this.database.updatePremise(state.targetPremiseId, {\n assertion: {\n text: state.assertionText!,\n tier: state.tier,\n },\n analysis: state.analysis ?? undefined,\n validity: {\n validFrom: state.validFrom,\n validUntil: state.validUntil,\n volatile: state.volatile,\n },\n embedding: state.embedding,\n });\n return { premise: updated };\n }\n\n logger.verbose(`[PremiseGraph.persist] Creating new premise for user ${state.userId}`);\n\n // Provenance confidence: prefer an explicit caller-supplied value; otherwise\n // derive it from the analyzer's felicity scores (how authoritative, sincere,\n // and clear the assertion is) rather than a blanket 1.0, so the stored\n // provenance reflects per-premise signal quality.\n const derivedConfidence = deriveProvenanceConfidence(state.analysis);\n const premise = await this.database.createPremise({\n userId: state.userId,\n assertion: {\n text: state.assertionText!,\n tier: state.tier,\n },\n provenance: {\n source: state.provenanceSource ?? 'explicit',\n sourceId: state.provenanceSourceId,\n confidence: state.provenanceConfidence ?? derivedConfidence,\n timestamp: new Date().toISOString(),\n },\n analysis: state.analysis ?? undefined,\n validity: {\n validFrom: state.validFrom,\n validUntil: state.validUntil,\n volatile: state.volatile,\n },\n embedding: state.embedding,\n });\n return { premise };\n });\n };\n\n const indexNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.index\", async () => {\n if (!state.premise) return {};\n\n logger.verbose(`[PremiseGraph.index] Scoring premise against user networks`);\n\n const assignmentMemberships = await this.database.getAssignmentNetworkMembershipsForUser(state.userId);\n const requestScope = state.scopeType && state.scopeId\n ? { scopeType: state.scopeType, scopeId: state.scopeId }\n : scopeFromNetworkId(state.networkScopeId);\n const indexIds = resolveAssignmentNetworkScope({\n memberships: assignmentMemberships,\n ...requestScope,\n });\n const scope = requestScope.scopeType ? \"network\" : \"global\";\n const assignments: Array<{ networkId: string; relevancyScore: number }> = [];\n const agentTimings: DebugMetaAgent[] = [];\n\n for (const networkId of indexIds) {\n try {\n const assignmentContext = await this.database.getNetworkAssignmentContext(networkId, state.userId);\n if (!assignmentContext) continue;\n const indexPrompt = assignmentContext.indexPrompt;\n const memberPrompt = assignmentContext.memberPrompt;\n const hasPrompts = !!indexPrompt?.trim() || !!memberPrompt?.trim();\n let rawScores: { indexScore?: number; memberScore?: number } | undefined;\n let reason: string | undefined;\n\n if (hasPrompts) {\n const start = Date.now();\n const result = await indexer.invoke({\n premiseText: state.assertionText!,\n indexPrompt: indexPrompt ?? \"\",\n memberPrompt: memberPrompt ?? undefined,\n });\n const timing: DebugMetaAgent = {\n name: \"premise-indexer\",\n durationMs: Date.now() - start,\n };\n rawScores = { indexScore: result.indexScore, memberScore: result.memberScore };\n reason = result.reasoning;\n agentTimings.push(timing);\n }\n\n const decision = buildNetworkAssignmentDecision({\n resourceType: \"premise\",\n mode: \"automatic\",\n scope,\n indexPrompt,\n memberPrompt,\n rawScores,\n evaluator: \"premise-indexer\",\n source: \"premise-graph\",\n reason,\n createdAt: new Date().toISOString(),\n });\n\n if (decision.assigned) {\n await this.database.assignPremiseToNetwork(\n state.premise.id,\n networkId,\n decision.finalScore,\n decision.metadata,\n );\n assignments.push({ networkId, relevancyScore: decision.finalScore });\n }\n } catch (err) {\n logger.verbose(`[PremiseGraph.index] Failed to score network ${networkId}, skipping: ${err}`);\n }\n }\n\n logger.verbose(`[PremiseGraph.index] Assigned to ${assignments.length} networks`);\n\n return { networkAssignments: assignments, agentTimings };\n });\n };\n\n const routeByMode = (state: typeof PremiseGraphState.State) => {\n if (state.error) return \"end\";\n if (state.operationMode === 'query') return \"query\";\n return \"analyze\";\n };\n\n const graph = new StateGraph(PremiseGraphState)\n .addNode(\"query\", queryNode)\n .addNode(\"analyze\", analyzeNode)\n .addNode(\"embed\", embedNode)\n .addNode(\"dedupe\", dedupeNode)\n .addNode(\"persist\", persistNode)\n .addNode(\"index\", indexNode)\n .addConditionalEdges(START, routeByMode, {\n query: \"query\",\n analyze: \"analyze\",\n end: END,\n })\n .addEdge(\"query\", END)\n .addEdge(\"analyze\", \"embed\")\n .addEdge(\"embed\", \"dedupe\")\n // A near-duplicate short-circuits straight to END (no persist, no index).\n .addConditionalEdges(\"dedupe\", (state: typeof PremiseGraphState.State) => (state.duplicateOf ? \"end\" : \"persist\"), {\n persist: \"persist\",\n end: END,\n })\n .addEdge(\"persist\", \"index\")\n .addEdge(\"index\", END);\n\n return graph.compile();\n }\n}\n"]}
1
+ {"version":3,"file":"premise.graph.js","sourceRoot":"/","sources":["premise/premise.graph.ts"],"names":[],"mappings":"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","sourcesContent":["import { StateGraph, START, END } from \"@langchain/langgraph\";\n\nimport { PremiseGraphState } from \"./premise.state.js\";\nimport { PremiseAnalyzer } from \"./premise.analyzer.js\";\nimport type { PremiseAnalyzerOutput } from \"./premise.analyzer.js\";\nimport { PremiseIndexer } from \"./premise.indexer.js\";\n\nimport { buildNetworkAssignmentDecision, resolveAssignmentNetworkScope } from \"../shared/assignment/network-assignment.policy.js\";\nimport { getAbortSignalConfig } from \"../shared/agent/model-signal.js\";\nimport { scopeFromNetworkId } from \"../shared/agent/tool.scope.js\";\nimport type { PremiseGraphDatabase, PremiseAnalysis } from \"../shared/interfaces/database.interface.js\";\nimport type { Embedder } from \"../shared/interfaces/embedder.interface.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { timed } from \"../shared/observability/performance.js\";\nimport type { DebugMetaAgent } from \"../chat/chat-streaming.types.js\";\n\nconst logger = protocolLogger(\"PremiseGraphFactory\");\nconst queryLog = protocolLogger(\"PremiseGraph:query\");\nconst analyzeLog = protocolLogger(\"PremiseGraph:analyze\");\nconst embedLog = protocolLogger(\"PremiseGraph:embed\");\nconst persistLog = protocolLogger(\"PremiseGraph:persist\");\nconst indexLog = protocolLogger(\"PremiseGraph:index\");\nconst dedupeLog = protocolLogger(\"PremiseGraph:dedupe\");\n\n/**\n * Minimum cosine similarity (0-1) at which a freshly-decomposed premise is treated\n * as a near-duplicate of an existing ACTIVE premise for the same user and skipped\n * on create. Tuned high so genuine paraphrases collapse while distinct facts (e.g.\n * \"I work at Google\" vs \"I worked at Google\") still persist. Override with\n * PREMISE_DEDUP_SIMILARITY.\n */\nconst DEDUP_SIMILARITY_THRESHOLD = (() => {\n const raw = Number(process.env.PREMISE_DEDUP_SIMILARITY);\n return Number.isFinite(raw) && raw > 0 && raw <= 1 ? raw : 0.93;\n})();\n\n/**\n * Derive a premise provenance confidence (0-1) from the analyzer's felicity scores.\n * Averages authority, sincerity, and clarity — the dimensions that speak to how\n * trustworthy the self-assertion is. Falls back to 1.0 when no analysis is present.\n */\nfunction deriveProvenanceConfidence(analysis: PremiseAnalysis | undefined): number {\n if (!analysis) return 1.0;\n const { felicityAuthority, felicitySincerity, felicityClarity } = analysis;\n const mean = (felicityAuthority + felicitySincerity + felicityClarity) / 3;\n if (!Number.isFinite(mean)) return 1.0;\n return Math.min(1, Math.max(0, mean));\n}\n\n/**\n * Graph factory for premise lifecycle: create, update, and query modes.\n */\nexport class PremiseGraphFactory {\n constructor(\n private database: PremiseGraphDatabase,\n private embedder: Embedder,\n private premiseIndexer: PremiseIndexer = new PremiseIndexer(),\n private premiseAnalyzer: { invoke(premiseText: string, profileContext?: string): Promise<PremiseAnalyzerOutput> } = new PremiseAnalyzer(),\n ) {}\n\n /**\n * Compiles and returns the premise lifecycle graph.\n *\n * @returns A compiled LangGraph graph handling create, update, and query modes.\n */\n public createGraph() {\n const analyzer = this.premiseAnalyzer;\n const indexer = this.premiseIndexer;\n\n const queryNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.query\", async () => {\n queryLog.verbose('Fetching premises for user', { userId: state.userId });\n const premises = await this.database.getPremisesForUser(state.userId, 'ACTIVE');\n return {\n readResult: {\n premises,\n count: premises.length,\n },\n };\n });\n };\n\n const analyzeNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.analyze\", async () => {\n if (!state.assertionText) {\n return { error: \"assertionText is required for create/update mode\" };\n }\n\n analyzeLog.verbose('Analyzing assertion text', { preview: state.assertionText.substring(0, 50) });\n\n const start = Date.now();\n const result = await analyzer.invoke(state.assertionText);\n const timing: DebugMetaAgent = {\n name: \"premise-analyzer\",\n durationMs: Date.now() - start,\n };\n\n const analysis: PremiseAnalysis = {\n speechActType: result.speechActType,\n felicityAuthority: result.felicityAuthority,\n felicitySincerity: result.felicitySincerity,\n felicityClarity: result.felicityClarity,\n semanticEntropy: result.semanticEntropy,\n };\n\n return { analysis, agentTimings: [timing] };\n });\n };\n\n const embedNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.embed\", async () => {\n if (state.error) return {};\n\n if (!state.assertionText) {\n return { error: \"assertionText is required for embedding\" };\n }\n\n embedLog.verbose(`Generating embedding for premise`);\n\n // Embedder.generate returns number[] | number[][], cast for single string input\n const embedding = await this.embedder.generate(state.assertionText, undefined, getAbortSignalConfig()) as number[];\n return { embedding };\n });\n };\n\n // ─────────────────────────────────────────────────────────\n // NODE: Dedupe (create mode only)\n // Skips persisting a near-duplicate of an existing ACTIVE premise for the same\n // user. Re-running similar input (e.g. repeated enrichment) therefore does not\n // accumulate near-identical premises. No-op for update mode, when no embedding\n // is available, or when the adapter does not implement findSimilarActivePremise.\n // ─────────────────────────────────────────────────────────\n const dedupeNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.dedupe\", async () => {\n if (state.error) return {};\n if (state.operationMode === 'update') return {};\n if (!state.embedding || state.embedding.length === 0) return {};\n if (typeof this.database.findSimilarActivePremise !== 'function') return {};\n\n const match = await this.database.findSimilarActivePremise({\n userId: state.userId,\n embedding: state.embedding,\n threshold: DEDUP_SIMILARITY_THRESHOLD,\n });\n\n if (match) {\n dedupeLog.verbose('Skipping near-duplicate premise', {\n similarity: Number(match.similarity.toFixed(3)),\n threshold: DEDUP_SIMILARITY_THRESHOLD,\n premiseId: match.premiseId,\n });\n return { duplicateOf: match };\n }\n return {};\n });\n };\n\n const persistNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.persist\", async () => {\n if (state.error) return {};\n\n if (state.operationMode === 'update' && !state.targetPremiseId) {\n return { error: \"targetPremiseId is required for update mode\" };\n }\n\n if (state.operationMode === 'update' && state.targetPremiseId) {\n persistLog.verbose('Updating premise', { premiseId: state.targetPremiseId });\n\n const updated = await this.database.updatePremise(state.targetPremiseId, {\n assertion: {\n text: state.assertionText!,\n tier: state.tier,\n },\n analysis: state.analysis ?? undefined,\n validity: {\n validFrom: state.validFrom,\n validUntil: state.validUntil,\n volatile: state.volatile,\n },\n embedding: state.embedding,\n });\n return { premise: updated };\n }\n\n persistLog.verbose('Creating new premise for user', { userId: state.userId });\n\n // Provenance confidence: prefer an explicit caller-supplied value; otherwise\n // derive it from the analyzer's felicity scores (how authoritative, sincere,\n // and clear the assertion is) rather than a blanket 1.0, so the stored\n // provenance reflects per-premise signal quality.\n const derivedConfidence = deriveProvenanceConfidence(state.analysis);\n const premise = await this.database.createPremise({\n userId: state.userId,\n assertion: {\n text: state.assertionText!,\n tier: state.tier,\n },\n provenance: {\n source: state.provenanceSource ?? 'explicit',\n sourceId: state.provenanceSourceId,\n confidence: state.provenanceConfidence ?? derivedConfidence,\n timestamp: new Date().toISOString(),\n },\n analysis: state.analysis ?? undefined,\n validity: {\n validFrom: state.validFrom,\n validUntil: state.validUntil,\n volatile: state.volatile,\n },\n embedding: state.embedding,\n });\n return { premise };\n });\n };\n\n const indexNode = async (state: typeof PremiseGraphState.State) => {\n return timed(\"PremiseGraph.index\", async () => {\n if (!state.premise) return {};\n\n indexLog.verbose(`Scoring premise against user networks`);\n\n const assignmentMemberships = await this.database.getAssignmentNetworkMembershipsForUser(state.userId);\n const requestScope = state.scopeType && state.scopeId\n ? { scopeType: state.scopeType, scopeId: state.scopeId }\n : scopeFromNetworkId(state.networkScopeId);\n const indexIds = resolveAssignmentNetworkScope({\n memberships: assignmentMemberships,\n ...requestScope,\n });\n const scope = requestScope.scopeType ? \"network\" : \"global\";\n const assignments: Array<{ networkId: string; relevancyScore: number }> = [];\n const agentTimings: DebugMetaAgent[] = [];\n\n for (const networkId of indexIds) {\n try {\n const assignmentContext = await this.database.getNetworkAssignmentContext(networkId, state.userId);\n if (!assignmentContext) continue;\n const indexPrompt = assignmentContext.indexPrompt;\n const memberPrompt = assignmentContext.memberPrompt;\n const hasPrompts = !!indexPrompt?.trim() || !!memberPrompt?.trim();\n let rawScores: { indexScore?: number; memberScore?: number } | undefined;\n let reason: string | undefined;\n\n if (hasPrompts) {\n const start = Date.now();\n const result = await indexer.invoke({\n premiseText: state.assertionText!,\n indexPrompt: indexPrompt ?? \"\",\n memberPrompt: memberPrompt ?? undefined,\n });\n const timing: DebugMetaAgent = {\n name: \"premise-indexer\",\n durationMs: Date.now() - start,\n };\n rawScores = { indexScore: result.indexScore, memberScore: result.memberScore };\n reason = result.reasoning;\n agentTimings.push(timing);\n }\n\n const decision = buildNetworkAssignmentDecision({\n resourceType: \"premise\",\n mode: \"automatic\",\n scope,\n indexPrompt,\n memberPrompt,\n rawScores,\n evaluator: \"premise-indexer\",\n source: \"premise-graph\",\n reason,\n createdAt: new Date().toISOString(),\n });\n\n if (decision.assigned) {\n await this.database.assignPremiseToNetwork(\n state.premise.id,\n networkId,\n decision.finalScore,\n decision.metadata,\n );\n assignments.push({ networkId, relevancyScore: decision.finalScore });\n }\n } catch (err) {\n indexLog.verbose('Failed to score network, skipping', { networkId, error: err });\n }\n }\n\n indexLog.verbose('Assigned to networks', { count: assignments.length });\n\n return { networkAssignments: assignments, agentTimings };\n });\n };\n\n const routeByMode = (state: typeof PremiseGraphState.State) => {\n if (state.error) return \"end\";\n if (state.operationMode === 'query') return \"query\";\n return \"analyze\";\n };\n\n const graph = new StateGraph(PremiseGraphState)\n .addNode(\"query\", queryNode)\n .addNode(\"analyze\", analyzeNode)\n .addNode(\"embed\", embedNode)\n .addNode(\"dedupe\", dedupeNode)\n .addNode(\"persist\", persistNode)\n .addNode(\"index\", indexNode)\n .addConditionalEdges(START, routeByMode, {\n query: \"query\",\n analyze: \"analyze\",\n end: END,\n })\n .addEdge(\"query\", END)\n .addEdge(\"analyze\", \"embed\")\n .addEdge(\"embed\", \"dedupe\")\n // A near-duplicate short-circuits straight to END (no persist, no index).\n .addConditionalEdges(\"dedupe\", (state: typeof PremiseGraphState.State) => (state.duplicateOf ? \"end\" : \"persist\"), {\n persist: \"persist\",\n end: END,\n })\n .addEdge(\"persist\", \"index\")\n .addEdge(\"index\", END);\n\n return graph.compile();\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"premise.indexer.d.ts","sourceRoot":"/","sources":["premise/premise.indexer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgCxB,QAAA,MAAM,cAAc;;;;;;;;;;;;EAIlB,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAElE;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA2C;;IAQxD;;;;;OAKG;IAEU,MAAM,CAAC,KAAK,EAAE;QACzB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAuBlC"}
1
+ {"version":3,"file":"premise.indexer.d.ts","sourceRoot":"/","sources":["premise/premise.indexer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAiCxB,QAAA,MAAM,cAAc;;;;;;;;;;;;EAIlB,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAElE;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA2C;;IAQxD;;;;;OAKG;IAEU,MAAM,CAAC,KAAK,EAAE;QACzB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAuBlC"}
@@ -14,6 +14,7 @@ import { Timed } from "../shared/observability/performance.js";
14
14
  import { createStructuredModel } from "../shared/agent/model.config.js";
15
15
  import { invokeWithAbortSignal } from "../shared/agent/model-signal.js";
16
16
  const logger = protocolLogger("PremiseIndexer");
17
+ const invokeLog = protocolLogger("PremiseIndexer:invoke");
17
18
  const systemPrompt = `
18
19
  You are a Premise Evaluator for a social networking protocol.
19
20
 
@@ -58,7 +59,7 @@ export class PremiseIndexer {
58
59
  * @returns Structured output with indexScore, memberScore, and reasoning.
59
60
  */
60
61
  async invoke(input) {
61
- logger.verbose(`[PremiseIndexer.invoke] Scoring premise against index`);
62
+ invokeLog.verbose(`Scoring premise against index`);
62
63
  const prompt = [
63
64
  "# Premise",
64
65
  input.premiseText,
@@ -1 +1 @@
1
- {"version":3,"file":"premise.indexer.js","sourceRoot":"/","sources":["premise/premise.indexer.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAExE,MAAM,MAAM,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAAC;AAEhD,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsBpB,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,qCAAqC,CAAC;IACpF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6CAA6C,CAAC;IAC7F,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;CACjE,CAAC,CAAC;AAIH;;GAEG;AACH,MAAM,OAAO,cAAc;IAGzB;QACE,IAAI,CAAC,KAAK,GAAG,qBAAqB,CAAC,gBAAgB,EAAE,cAAc,EAAE;YACnE,IAAI,EAAE,iBAAiB;SACxB,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IAEU,AAAN,KAAK,CAAC,MAAM,CAAC,KAKnB;QACC,MAAM,CAAC,OAAO,CAAC,uDAAuD,CAAC,CAAC;QAExE,MAAM,MAAM,GAAG;YACb,WAAW;YACX,KAAK,CAAC,WAAW;YACjB,EAAE;YACF,kBAAkB;YAClB,KAAK,CAAC,WAAW,IAAI,8BAA8B;YACnD,EAAE;YACF,iBAAiB;YACjB,KAAK,CAAC,YAAY,IAAI,6BAA6B;YACnD,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,mBAAmB,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACjF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,MAAM,QAAQ,GAAG;YACf,IAAI,aAAa,CAAC,YAAY,CAAC;YAC/B,IAAI,YAAY,CAAC,MAAM,CAAC;SACzB,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACjE,OAAO,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;CACF;AA5Bc;IADZ,KAAK,EAAE;;;;4CA4BP","sourcesContent":["import { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\nimport { z } from \"zod\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { createStructuredModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"PremiseIndexer\");\n\nconst systemPrompt = `\nYou are a Premise Evaluator for a social networking protocol.\n\nTASK:\nDetermine if a User Premise (a self-descriptive proposition about who someone is) is relevant to a specific Index (community).\n\nINPUTS:\n1. Premise: A self-description the user asserts about themselves.\n2. Network Prompt: The purpose/scope of the target community (Index).\n3. Member Prompt: The specific sharing preferences of the user in that community (optional).\n\nSCORING RUBRIC:\n- 0.9-1.0: Highly relevant. The premise directly relates to the community's purpose.\n- 0.7-0.8: Good relevance. The premise is clearly adjacent to the community's focus.\n- 0.5-0.6: Moderate. Borderline relevance.\n- 0.3-0.4: Low relevance. Weak connection.\n- 0.0-0.2: Not relevant. The premise has no connection to this community.\n\nOUTPUT RULES:\n- Provide indexScore based on how well the Premise fits the Network Prompt.\n- Provide memberScore based on how well the Premise fits the Member Prompt (if provided). If Member Prompt is missing/empty, return 0.0.\n- Provide concise reasoning.\n`;\n\nconst responseFormat = z.object({\n indexScore: z.number().min(0).max(1).describe(\"Score for index relevance (0.0-1.0)\"),\n memberScore: z.number().min(0).max(1).describe(\"Score for member preference match (0.0-1.0)\"),\n reasoning: z.string().describe(\"Brief reasoning for the scores\"),\n});\n\nexport type PremiseIndexerOutput = z.infer<typeof responseFormat>;\n\n/**\n * Scores a premise's relevancy to a network based on the index and member prompts.\n */\nexport class PremiseIndexer {\n private model: ReturnType<typeof createStructuredModel>;\n\n constructor() {\n this.model = createStructuredModel(\"premiseIndexer\", responseFormat, {\n name: \"premise_indexer\"\n });\n }\n\n /**\n * Scores the relevancy of a premise to a network index and member preferences.\n *\n * @param input - The premise text, network prompt, member prompt, and optional network context.\n * @returns Structured output with indexScore, memberScore, and reasoning.\n */\n @Timed()\n public async invoke(input: {\n premiseText: string;\n indexPrompt: string;\n memberPrompt?: string;\n networkContext?: string;\n }): Promise<PremiseIndexerOutput> {\n logger.verbose(`[PremiseIndexer.invoke] Scoring premise against index`);\n\n const prompt = [\n \"# Premise\",\n input.premiseText,\n \"\",\n \"# Network Prompt\",\n input.indexPrompt || \"(No network prompt provided)\",\n \"\",\n \"# Member Prompt\",\n input.memberPrompt || \"(No member prompt provided)\",\n ...(input.networkContext ? [\"\", \"# Network Context\", input.networkContext] : []),\n ].join(\"\\n\");\n\n const messages = [\n new SystemMessage(systemPrompt),\n new HumanMessage(prompt),\n ];\n\n const result = await invokeWithAbortSignal(this.model, messages);\n return responseFormat.parse(result);\n }\n}\n"]}
1
+ {"version":3,"file":"premise.indexer.js","sourceRoot":"/","sources":["premise/premise.indexer.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAExE,MAAM,MAAM,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAAC;AAChD,MAAM,SAAS,GAAG,cAAc,CAAC,uBAAuB,CAAC,CAAC;AAE1D,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsBpB,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,qCAAqC,CAAC;IACpF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6CAA6C,CAAC;IAC7F,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;CACjE,CAAC,CAAC;AAIH;;GAEG;AACH,MAAM,OAAO,cAAc;IAGzB;QACE,IAAI,CAAC,KAAK,GAAG,qBAAqB,CAAC,gBAAgB,EAAE,cAAc,EAAE;YACnE,IAAI,EAAE,iBAAiB;SACxB,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IAEU,AAAN,KAAK,CAAC,MAAM,CAAC,KAKnB;QACC,SAAS,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC;QAEnD,MAAM,MAAM,GAAG;YACb,WAAW;YACX,KAAK,CAAC,WAAW;YACjB,EAAE;YACF,kBAAkB;YAClB,KAAK,CAAC,WAAW,IAAI,8BAA8B;YACnD,EAAE;YACF,iBAAiB;YACjB,KAAK,CAAC,YAAY,IAAI,6BAA6B;YACnD,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,mBAAmB,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACjF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,MAAM,QAAQ,GAAG;YACf,IAAI,aAAa,CAAC,YAAY,CAAC;YAC/B,IAAI,YAAY,CAAC,MAAM,CAAC;SACzB,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACjE,OAAO,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;CACF;AA5Bc;IADZ,KAAK,EAAE;;;;4CA4BP","sourcesContent":["import { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\nimport { z } from \"zod\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport { Timed } from \"../shared/observability/performance.js\";\nimport { createStructuredModel } from \"../shared/agent/model.config.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"PremiseIndexer\");\nconst invokeLog = protocolLogger(\"PremiseIndexer:invoke\");\n\nconst systemPrompt = `\nYou are a Premise Evaluator for a social networking protocol.\n\nTASK:\nDetermine if a User Premise (a self-descriptive proposition about who someone is) is relevant to a specific Index (community).\n\nINPUTS:\n1. Premise: A self-description the user asserts about themselves.\n2. Network Prompt: The purpose/scope of the target community (Index).\n3. Member Prompt: The specific sharing preferences of the user in that community (optional).\n\nSCORING RUBRIC:\n- 0.9-1.0: Highly relevant. The premise directly relates to the community's purpose.\n- 0.7-0.8: Good relevance. The premise is clearly adjacent to the community's focus.\n- 0.5-0.6: Moderate. Borderline relevance.\n- 0.3-0.4: Low relevance. Weak connection.\n- 0.0-0.2: Not relevant. The premise has no connection to this community.\n\nOUTPUT RULES:\n- Provide indexScore based on how well the Premise fits the Network Prompt.\n- Provide memberScore based on how well the Premise fits the Member Prompt (if provided). If Member Prompt is missing/empty, return 0.0.\n- Provide concise reasoning.\n`;\n\nconst responseFormat = z.object({\n indexScore: z.number().min(0).max(1).describe(\"Score for index relevance (0.0-1.0)\"),\n memberScore: z.number().min(0).max(1).describe(\"Score for member preference match (0.0-1.0)\"),\n reasoning: z.string().describe(\"Brief reasoning for the scores\"),\n});\n\nexport type PremiseIndexerOutput = z.infer<typeof responseFormat>;\n\n/**\n * Scores a premise's relevancy to a network based on the index and member prompts.\n */\nexport class PremiseIndexer {\n private model: ReturnType<typeof createStructuredModel>;\n\n constructor() {\n this.model = createStructuredModel(\"premiseIndexer\", responseFormat, {\n name: \"premise_indexer\"\n });\n }\n\n /**\n * Scores the relevancy of a premise to a network index and member preferences.\n *\n * @param input - The premise text, network prompt, member prompt, and optional network context.\n * @returns Structured output with indexScore, memberScore, and reasoning.\n */\n @Timed()\n public async invoke(input: {\n premiseText: string;\n indexPrompt: string;\n memberPrompt?: string;\n networkContext?: string;\n }): Promise<PremiseIndexerOutput> {\n invokeLog.verbose(`Scoring premise against index`);\n\n const prompt = [\n \"# Premise\",\n input.premiseText,\n \"\",\n \"# Network Prompt\",\n input.indexPrompt || \"(No network prompt provided)\",\n \"\",\n \"# Member Prompt\",\n input.memberPrompt || \"(No member prompt provided)\",\n ...(input.networkContext ? [\"\", \"# Network Context\", input.networkContext] : []),\n ].join(\"\\n\");\n\n const messages = [\n new SystemMessage(systemPrompt),\n new HumanMessage(prompt),\n ];\n\n const result = await invokeWithAbortSignal(this.model, messages);\n return responseFormat.parse(result);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"premise.tools.d.ts","sourceRoot":"/","sources":["premise/premise.tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAQ5E,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,SAuRxE"}
1
+ {"version":3,"file":"premise.tools.d.ts","sourceRoot":"/","sources":["premise/premise.tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAY5E,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,SAuRxE"}
@@ -3,6 +3,10 @@ import { success, error, UUID_REGEX } from "../shared/agent/tool.helpers.js";
3
3
  import { protocolLogger } from "../shared/observability/protocol.logger.js";
4
4
  import { invokeWithAbortSignal } from "../shared/agent/model-signal.js";
5
5
  const logger = protocolLogger("ChatTools:Premise");
6
+ const createPremiseLog = protocolLogger("ChatTools:Premise:createPremise");
7
+ const readPremisesLog = protocolLogger("ChatTools:Premise:readPremises");
8
+ const updatePremiseLog = protocolLogger("ChatTools:Premise:updatePremise");
9
+ const retractPremiseLog = protocolLogger("ChatTools:Premise:retractPremise");
6
10
  export function createPremiseTools(defineTool, deps) {
7
11
  const database = deps.database;
8
12
  const premiseGraph = deps.graphs.premise;
@@ -38,7 +42,7 @@ export function createPremiseTools(defineTool, deps) {
38
42
  const scopeEnvelope = context.scopeType && context.scopeId
39
43
  ? { scopeType: context.scopeType, scopeId: context.scopeId }
40
44
  : {};
41
- logger.verbose(`[createPremise] Creating premise for user ${context.userId}: "${query.text.substring(0, 60)}..."`);
45
+ createPremiseLog.verbose('Creating premise for user', { userId: context.userId, preview: query.text.substring(0, 60) });
42
46
  const result = await invokeWithAbortSignal(premiseGraph, {
43
47
  userId: context.userId,
44
48
  assertionText: query.text,
@@ -91,7 +95,7 @@ export function createPremiseTools(defineTool, deps) {
91
95
  if (query.userId?.trim() && !UUID_REGEX.test(query.userId.trim())) {
92
96
  return error("Invalid userId format.");
93
97
  }
94
- logger.verbose(`[readPremises] Fetching premises for user ${targetUserId}`);
98
+ readPremisesLog.verbose('Fetching premises for user', { userId: targetUserId });
95
99
  // Query DB directly (bypassing graph) to support status filtering.
96
100
  // The graph's query node hardcodes ACTIVE status, so includeRetracted
97
101
  // would be dead code if we routed through it.
@@ -145,7 +149,7 @@ export function createPremiseTools(defineTool, deps) {
145
149
  if (existing.status === "RETRACTED") {
146
150
  return error("Cannot update a retracted premise. Retracted premises are immutable.");
147
151
  }
148
- logger.verbose(`[updatePremise] Updating premise ${query.premiseId} for user ${context.userId}`);
152
+ updatePremiseLog.verbose('Updating premise for user', { premiseId: query.premiseId, userId: context.userId });
149
153
  // When text is unchanged, skip the graph (avoids unnecessary LLM
150
154
  // re-analysis and non-deterministic re-embedding). Only route through
151
155
  // the graph when the assertion text actually changes.
@@ -229,7 +233,7 @@ export function createPremiseTools(defineTool, deps) {
229
233
  if (existing.status === "RETRACTED") {
230
234
  return error("Premise is already retracted.");
231
235
  }
232
- logger.verbose(`[retractPremise] Retracting premise ${query.premiseId} for user ${context.userId}`);
236
+ retractPremiseLog.verbose('Retracting premise for user', { premiseId: query.premiseId, userId: context.userId });
233
237
  await database.updatePremise(query.premiseId, {
234
238
  status: "RETRACTED",
235
239
  retractedAt: new Date(),
@@ -1 +1 @@
1
- {"version":3,"file":"premise.tools.js","sourceRoot":"/","sources":["premise/premise.tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport type { DefineTool, ToolDeps } from \"../shared/agent/tool.helpers.js\";\nimport { success, error, UUID_REGEX } from \"../shared/agent/tool.helpers.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport type { PremiseRecord, PremiseValidity } from \"../shared/interfaces/database.interface.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"ChatTools:Premise\");\n\nexport function createPremiseTools(defineTool: DefineTool, deps: ToolDeps) {\n const database = deps.database;\n const premiseGraph = deps.graphs.premise;\n\n // ─────────────────────────────────────────────────────────────────────────────\n // PREMISE CRUD\n // ─────────────────────────────────────────────────────────────────────────────\n\n const createPremise = defineTool({\n name: \"create_premise\",\n description:\n \"Creates a premise — a self-descriptive proposition the user asserts about themselves. \" +\n \"Premises are the foundational facts that shape how the system understands who you are \" +\n \"and what contexts you inhabit.\\n\\n\" +\n \"**Tiers:**\\n\" +\n \"- `assertive` (default): stable identity facts (e.g. 'I am a software engineer', 'I live in Berlin'). \" +\n \"Use for things that are durably true and not time-bound.\\n\" +\n \"- `contextual`: temporal or situational facts (e.g. 'I am attending DevCon this week', \" +\n \"'I am fundraising for my Series A right now'). Use when the user shares something time-bound \" +\n \"or context-specific. These default to `volatile: true`.\\n\\n\" +\n \"**When to use:** Call this whenever the user shares a fact about themselves in first person \" +\n \"('I am', 'I work at', 'I just joined', 'I am currently'). Do not infer premises from vague \" +\n \"statements — only create them when the user is clearly asserting something about themselves.\",\n querySchema: z.object({\n text: z.string().trim().min(1).describe(\"The premise text — a self-descriptive proposition in first person, e.g. 'I am a machine learning researcher at MIT'.\"),\n tier: z.enum([\"assertive\", \"contextual\"]).default(\"assertive\").describe(\"Tier of the premise. 'assertive' = stable identity fact. 'contextual' = temporal/situational. Defaults to 'assertive'.\"),\n validFrom: z.string().datetime().optional().describe(\"ISO 8601 date-time string for when this premise becomes valid. Omit for immediate.\"),\n validUntil: z.string().datetime().optional().describe(\"ISO 8601 date-time string for when this premise expires. Recommended for contextual premises with a known end date; omit if open-ended.\"),\n volatile: z.boolean().optional().describe(\"Whether this premise should be automatically retracted when it expires. Defaults to true for contextual tier, false for assertive.\"),\n }),\n handler: async ({ context, query }) => {\n if (!premiseGraph) {\n return error(\"Premise graph not available.\");\n }\n\n const effectiveVolatile = query.volatile ?? (query.tier === \"contextual\" ? true : false);\n const scopeEnvelope = context.scopeType && context.scopeId\n ? { scopeType: context.scopeType, scopeId: context.scopeId }\n : {};\n\n logger.verbose(`[createPremise] Creating premise for user ${context.userId}: \"${query.text.substring(0, 60)}...\"`);\n\n const result = await invokeWithAbortSignal(premiseGraph, {\n userId: context.userId,\n assertionText: query.text,\n tier: query.tier,\n validFrom: query.validFrom,\n validUntil: query.validUntil,\n volatile: effectiveVolatile,\n operationMode: \"create\",\n ...scopeEnvelope,\n });\n\n if (result.error) {\n return error(result.error);\n }\n\n if (!result.premise) {\n return error(\"Premise creation failed — no premise returned.\");\n }\n\n const premise = result.premise;\n const indexesAssigned = result.networkAssignments?.length ?? 0;\n const analysisSummary = premise.analysis\n ? `speechActType: ${premise.analysis.speechActType}, clarity: ${premise.analysis.felicityClarity?.toFixed(2) ?? \"n/a\"}`\n : \"no analysis\";\n\n const createResult = success({\n id: premise.id,\n assertion: premise.assertion.text,\n tier: premise.assertion.tier,\n analysisSummary,\n indexesAssigned,\n message: `Premise created and assigned to ${indexesAssigned} index${indexesAssigned === 1 ? \"\" : \"es\"}.`,\n });\n return createResult;\n },\n });\n\n const readPremises = defineTool({\n name: \"read_premises\",\n description:\n \"Retrieves premises — the self-descriptive propositions a user has asserted about themselves. \" +\n \"Premises represent stable identity facts (assertive) and temporal context (contextual).\\n\\n\" +\n \"**Usage modes:**\\n\" +\n \"- No parameters: returns the caller's own active premises.\\n\" +\n \"- With `userId`: returns that user's premises (use when reviewing another member's context).\\n\" +\n \"- With `includeRetracted: true`: returns all premises regardless of status (active, retracted, expired) for history review.\\n\\n\" +\n \"**When to use:** Call before creating a premise to check if it already exists. \" +\n \"Call when the user asks what they have shared about themselves, or to review their current context. \" +\n \"Each premise includes: id, text, tier, status, analysis summary, and validity range.\",\n querySchema: z.object({\n userId: z.string().optional().describe(\"User ID to fetch premises for. Omit to fetch the current user's own premises.\"),\n includeRetracted: z.boolean().default(false).describe(\"When true, returns all premises regardless of status (active, retracted, expired). Defaults to false (active only).\"),\n }),\n handler: async ({ context, query }) => {\n const targetUserId = query.userId?.trim() || context.userId;\n\n if (query.userId?.trim() && !UUID_REGEX.test(query.userId.trim())) {\n return error(\"Invalid userId format.\");\n }\n\n logger.verbose(`[readPremises] Fetching premises for user ${targetUserId}`);\n\n // Query DB directly (bypassing graph) to support status filtering.\n // The graph's query node hardcodes ACTIVE status, so includeRetracted\n // would be dead code if we routed through it.\n const statusFilter = query.includeRetracted ? undefined : \"ACTIVE\" as const;\n const premises = await database.getPremisesForUser(targetUserId, statusFilter);\n\n const mapped = premises.map((p: PremiseRecord) => ({\n id: p.id,\n text: p.assertion.text,\n tier: p.assertion.tier,\n status: p.status,\n analysisSummary: p.analysis\n ? `speechActType: ${p.analysis.speechActType ?? \"n/a\"}, clarity: ${p.analysis.felicityClarity?.toFixed(2) ?? \"n/a\"}`\n : \"no analysis\",\n validFrom: p.validity.validFrom ?? null,\n validUntil: p.validity.validUntil ?? null,\n volatile: p.validity.volatile ?? false,\n }));\n\n return success({\n premises: mapped,\n count: mapped.length,\n });\n },\n });\n\n const updatePremise = defineTool({\n name: \"update_premise\",\n description:\n \"Modifies an existing premise. Updating the text triggers re-analysis and re-embedding, \" +\n \"which may change how it influences opportunity discovery. \" +\n \"Use when the user corrects or refines something they previously stated about themselves, \" +\n \"or when validity dates need adjustment.\\n\\n\" +\n \"**When to use:** When the user says 'actually, I meant...', 'update my premise about...', \" +\n \"or provides a corrected version of a previously stated fact. \" +\n \"Requires the premise ID — call read_premises first if you don't have it.\",\n querySchema: z.object({\n premiseId: z.string().describe(\"UUID of the premise to update. Get from read_premises.\"),\n text: z.string().trim().min(1).optional().describe(\"New assertion text. Triggers re-analysis and re-embedding when provided.\"),\n validFrom: z.string().datetime().optional().describe(\"New ISO 8601 valid-from date-time.\"),\n validUntil: z.string().datetime().optional().describe(\"New ISO 8601 valid-until date-time.\"),\n volatile: z.boolean().optional().describe(\"Update the volatile flag.\"),\n }),\n handler: async ({ context, query }) => {\n if (!UUID_REGEX.test(query.premiseId)) {\n return error(\"Invalid premiseId format.\");\n }\n\n const existing = await database.getPremise(query.premiseId);\n if (!existing) {\n return error(\"Premise not found.\");\n }\n if (existing.userId !== context.userId) {\n return error(\"You can only update your own premises.\");\n }\n if (existing.status === \"RETRACTED\") {\n return error(\"Cannot update a retracted premise. Retracted premises are immutable.\");\n }\n\n logger.verbose(`[updatePremise] Updating premise ${query.premiseId} for user ${context.userId}`);\n\n // When text is unchanged, skip the graph (avoids unnecessary LLM\n // re-analysis and non-deterministic re-embedding). Only route through\n // the graph when the assertion text actually changes.\n if (query.text === undefined) {\n const hasValidityChange =\n query.validFrom !== undefined ||\n query.validUntil !== undefined ||\n query.volatile !== undefined;\n\n if (!hasValidityChange) {\n return error(\"No fields to update. Provide text, validFrom, validUntil, or volatile.\");\n }\n\n const mergedValidity: PremiseValidity = {\n ...existing.validity,\n ...(query.validFrom !== undefined && { validFrom: query.validFrom }),\n ...(query.validUntil !== undefined && { validUntil: query.validUntil }),\n ...(query.volatile !== undefined && { volatile: query.volatile }),\n };\n\n const updated = await database.updatePremise(query.premiseId, { validity: mergedValidity });\n\n const metadataResult = success({\n id: updated.id,\n assertion: updated.assertion.text,\n tier: updated.assertion.tier,\n status: updated.status,\n message: \"Premise updated successfully (metadata only, no re-analysis).\",\n });\n return metadataResult;\n }\n\n // Text change requires the graph for re-analysis and re-embedding\n if (!premiseGraph) {\n return error(\"Premise graph not available.\");\n }\n\n const result = await invokeWithAbortSignal(premiseGraph, {\n userId: context.userId,\n assertionText: query.text,\n tier: existing.assertion.tier,\n validFrom: query.validFrom ?? existing.validity.validFrom ?? undefined,\n validUntil: query.validUntil ?? existing.validity.validUntil ?? undefined,\n volatile: query.volatile ?? existing.validity.volatile,\n operationMode: \"update\",\n targetPremiseId: query.premiseId,\n ...(context.scopeType && context.scopeId ? { scopeType: context.scopeType, scopeId: context.scopeId } : {}),\n });\n\n if (result.error) {\n return error(result.error);\n }\n\n if (!result.premise) {\n return error(\"Premise update failed — no updated premise returned.\");\n }\n\n const updated = result.premise;\n\n const updateResult = success({\n id: updated.id,\n assertion: updated.assertion.text,\n tier: updated.assertion.tier,\n status: updated.status,\n message: \"Premise updated successfully.\",\n });\n return updateResult;\n },\n });\n\n const retractPremise = defineTool({\n name: \"retract_premise\",\n description:\n \"Retracts a premise — a soft delete that preserves the history of what was asserted. \" +\n \"Retracted premises are no longer active but remain in the audit trail. \" +\n \"Use when the user explicitly wants to remove something they previously stated about themselves, \" +\n \"or when a contextual premise is no longer true.\\n\\n\" +\n \"**When to use:** When the user says 'remove my premise about...', 'I no longer...', \" +\n \"or 'that's not true anymore'. Do not retract premises proactively — only on explicit user instruction.\",\n querySchema: z.object({\n premiseId: z.string().describe(\"UUID of the premise to retract. Get from read_premises.\"),\n }),\n handler: async ({ context, query }) => {\n if (!UUID_REGEX.test(query.premiseId)) {\n return error(\"Invalid premiseId format.\");\n }\n\n const existing = await database.getPremise(query.premiseId);\n if (!existing) {\n return error(\"Premise not found.\");\n }\n if (existing.userId !== context.userId) {\n return error(\"You can only retract your own premises.\");\n }\n if (existing.status === \"RETRACTED\") {\n return error(\"Premise is already retracted.\");\n }\n\n logger.verbose(`[retractPremise] Retracting premise ${query.premiseId} for user ${context.userId}`);\n\n await database.updatePremise(query.premiseId, {\n status: \"RETRACTED\",\n retractedAt: new Date(),\n });\n\n const retractResult = success({\n id: query.premiseId,\n message: \"Premise retracted successfully.\",\n });\n return retractResult;\n },\n });\n\n return [createPremise, readPremises, updatePremise, retractPremise];\n}\n"]}
1
+ {"version":3,"file":"premise.tools.js","sourceRoot":"/","sources":["premise/premise.tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport type { DefineTool, ToolDeps } from \"../shared/agent/tool.helpers.js\";\nimport { success, error, UUID_REGEX } from \"../shared/agent/tool.helpers.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport type { PremiseRecord, PremiseValidity } from \"../shared/interfaces/database.interface.js\";\nimport { invokeWithAbortSignal } from \"../shared/agent/model-signal.js\";\n\nconst logger = protocolLogger(\"ChatTools:Premise\");\nconst createPremiseLog = protocolLogger(\"ChatTools:Premise:createPremise\");\nconst readPremisesLog = protocolLogger(\"ChatTools:Premise:readPremises\");\nconst updatePremiseLog = protocolLogger(\"ChatTools:Premise:updatePremise\");\nconst retractPremiseLog = protocolLogger(\"ChatTools:Premise:retractPremise\");\n\nexport function createPremiseTools(defineTool: DefineTool, deps: ToolDeps) {\n const database = deps.database;\n const premiseGraph = deps.graphs.premise;\n\n // ─────────────────────────────────────────────────────────────────────────────\n // PREMISE CRUD\n // ─────────────────────────────────────────────────────────────────────────────\n\n const createPremise = defineTool({\n name: \"create_premise\",\n description:\n \"Creates a premise — a self-descriptive proposition the user asserts about themselves. \" +\n \"Premises are the foundational facts that shape how the system understands who you are \" +\n \"and what contexts you inhabit.\\n\\n\" +\n \"**Tiers:**\\n\" +\n \"- `assertive` (default): stable identity facts (e.g. 'I am a software engineer', 'I live in Berlin'). \" +\n \"Use for things that are durably true and not time-bound.\\n\" +\n \"- `contextual`: temporal or situational facts (e.g. 'I am attending DevCon this week', \" +\n \"'I am fundraising for my Series A right now'). Use when the user shares something time-bound \" +\n \"or context-specific. These default to `volatile: true`.\\n\\n\" +\n \"**When to use:** Call this whenever the user shares a fact about themselves in first person \" +\n \"('I am', 'I work at', 'I just joined', 'I am currently'). Do not infer premises from vague \" +\n \"statements — only create them when the user is clearly asserting something about themselves.\",\n querySchema: z.object({\n text: z.string().trim().min(1).describe(\"The premise text — a self-descriptive proposition in first person, e.g. 'I am a machine learning researcher at MIT'.\"),\n tier: z.enum([\"assertive\", \"contextual\"]).default(\"assertive\").describe(\"Tier of the premise. 'assertive' = stable identity fact. 'contextual' = temporal/situational. Defaults to 'assertive'.\"),\n validFrom: z.string().datetime().optional().describe(\"ISO 8601 date-time string for when this premise becomes valid. Omit for immediate.\"),\n validUntil: z.string().datetime().optional().describe(\"ISO 8601 date-time string for when this premise expires. Recommended for contextual premises with a known end date; omit if open-ended.\"),\n volatile: z.boolean().optional().describe(\"Whether this premise should be automatically retracted when it expires. Defaults to true for contextual tier, false for assertive.\"),\n }),\n handler: async ({ context, query }) => {\n if (!premiseGraph) {\n return error(\"Premise graph not available.\");\n }\n\n const effectiveVolatile = query.volatile ?? (query.tier === \"contextual\" ? true : false);\n const scopeEnvelope = context.scopeType && context.scopeId\n ? { scopeType: context.scopeType, scopeId: context.scopeId }\n : {};\n\n createPremiseLog.verbose('Creating premise for user', { userId: context.userId, preview: query.text.substring(0, 60) });\n\n const result = await invokeWithAbortSignal(premiseGraph, {\n userId: context.userId,\n assertionText: query.text,\n tier: query.tier,\n validFrom: query.validFrom,\n validUntil: query.validUntil,\n volatile: effectiveVolatile,\n operationMode: \"create\",\n ...scopeEnvelope,\n });\n\n if (result.error) {\n return error(result.error);\n }\n\n if (!result.premise) {\n return error(\"Premise creation failed — no premise returned.\");\n }\n\n const premise = result.premise;\n const indexesAssigned = result.networkAssignments?.length ?? 0;\n const analysisSummary = premise.analysis\n ? `speechActType: ${premise.analysis.speechActType}, clarity: ${premise.analysis.felicityClarity?.toFixed(2) ?? \"n/a\"}`\n : \"no analysis\";\n\n const createResult = success({\n id: premise.id,\n assertion: premise.assertion.text,\n tier: premise.assertion.tier,\n analysisSummary,\n indexesAssigned,\n message: `Premise created and assigned to ${indexesAssigned} index${indexesAssigned === 1 ? \"\" : \"es\"}.`,\n });\n return createResult;\n },\n });\n\n const readPremises = defineTool({\n name: \"read_premises\",\n description:\n \"Retrieves premises — the self-descriptive propositions a user has asserted about themselves. \" +\n \"Premises represent stable identity facts (assertive) and temporal context (contextual).\\n\\n\" +\n \"**Usage modes:**\\n\" +\n \"- No parameters: returns the caller's own active premises.\\n\" +\n \"- With `userId`: returns that user's premises (use when reviewing another member's context).\\n\" +\n \"- With `includeRetracted: true`: returns all premises regardless of status (active, retracted, expired) for history review.\\n\\n\" +\n \"**When to use:** Call before creating a premise to check if it already exists. \" +\n \"Call when the user asks what they have shared about themselves, or to review their current context. \" +\n \"Each premise includes: id, text, tier, status, analysis summary, and validity range.\",\n querySchema: z.object({\n userId: z.string().optional().describe(\"User ID to fetch premises for. Omit to fetch the current user's own premises.\"),\n includeRetracted: z.boolean().default(false).describe(\"When true, returns all premises regardless of status (active, retracted, expired). Defaults to false (active only).\"),\n }),\n handler: async ({ context, query }) => {\n const targetUserId = query.userId?.trim() || context.userId;\n\n if (query.userId?.trim() && !UUID_REGEX.test(query.userId.trim())) {\n return error(\"Invalid userId format.\");\n }\n\n readPremisesLog.verbose('Fetching premises for user', { userId: targetUserId });\n\n // Query DB directly (bypassing graph) to support status filtering.\n // The graph's query node hardcodes ACTIVE status, so includeRetracted\n // would be dead code if we routed through it.\n const statusFilter = query.includeRetracted ? undefined : \"ACTIVE\" as const;\n const premises = await database.getPremisesForUser(targetUserId, statusFilter);\n\n const mapped = premises.map((p: PremiseRecord) => ({\n id: p.id,\n text: p.assertion.text,\n tier: p.assertion.tier,\n status: p.status,\n analysisSummary: p.analysis\n ? `speechActType: ${p.analysis.speechActType ?? \"n/a\"}, clarity: ${p.analysis.felicityClarity?.toFixed(2) ?? \"n/a\"}`\n : \"no analysis\",\n validFrom: p.validity.validFrom ?? null,\n validUntil: p.validity.validUntil ?? null,\n volatile: p.validity.volatile ?? false,\n }));\n\n return success({\n premises: mapped,\n count: mapped.length,\n });\n },\n });\n\n const updatePremise = defineTool({\n name: \"update_premise\",\n description:\n \"Modifies an existing premise. Updating the text triggers re-analysis and re-embedding, \" +\n \"which may change how it influences opportunity discovery. \" +\n \"Use when the user corrects or refines something they previously stated about themselves, \" +\n \"or when validity dates need adjustment.\\n\\n\" +\n \"**When to use:** When the user says 'actually, I meant...', 'update my premise about...', \" +\n \"or provides a corrected version of a previously stated fact. \" +\n \"Requires the premise ID — call read_premises first if you don't have it.\",\n querySchema: z.object({\n premiseId: z.string().describe(\"UUID of the premise to update. Get from read_premises.\"),\n text: z.string().trim().min(1).optional().describe(\"New assertion text. Triggers re-analysis and re-embedding when provided.\"),\n validFrom: z.string().datetime().optional().describe(\"New ISO 8601 valid-from date-time.\"),\n validUntil: z.string().datetime().optional().describe(\"New ISO 8601 valid-until date-time.\"),\n volatile: z.boolean().optional().describe(\"Update the volatile flag.\"),\n }),\n handler: async ({ context, query }) => {\n if (!UUID_REGEX.test(query.premiseId)) {\n return error(\"Invalid premiseId format.\");\n }\n\n const existing = await database.getPremise(query.premiseId);\n if (!existing) {\n return error(\"Premise not found.\");\n }\n if (existing.userId !== context.userId) {\n return error(\"You can only update your own premises.\");\n }\n if (existing.status === \"RETRACTED\") {\n return error(\"Cannot update a retracted premise. Retracted premises are immutable.\");\n }\n\n updatePremiseLog.verbose('Updating premise for user', { premiseId: query.premiseId, userId: context.userId });\n\n // When text is unchanged, skip the graph (avoids unnecessary LLM\n // re-analysis and non-deterministic re-embedding). Only route through\n // the graph when the assertion text actually changes.\n if (query.text === undefined) {\n const hasValidityChange =\n query.validFrom !== undefined ||\n query.validUntil !== undefined ||\n query.volatile !== undefined;\n\n if (!hasValidityChange) {\n return error(\"No fields to update. Provide text, validFrom, validUntil, or volatile.\");\n }\n\n const mergedValidity: PremiseValidity = {\n ...existing.validity,\n ...(query.validFrom !== undefined && { validFrom: query.validFrom }),\n ...(query.validUntil !== undefined && { validUntil: query.validUntil }),\n ...(query.volatile !== undefined && { volatile: query.volatile }),\n };\n\n const updated = await database.updatePremise(query.premiseId, { validity: mergedValidity });\n\n const metadataResult = success({\n id: updated.id,\n assertion: updated.assertion.text,\n tier: updated.assertion.tier,\n status: updated.status,\n message: \"Premise updated successfully (metadata only, no re-analysis).\",\n });\n return metadataResult;\n }\n\n // Text change requires the graph for re-analysis and re-embedding\n if (!premiseGraph) {\n return error(\"Premise graph not available.\");\n }\n\n const result = await invokeWithAbortSignal(premiseGraph, {\n userId: context.userId,\n assertionText: query.text,\n tier: existing.assertion.tier,\n validFrom: query.validFrom ?? existing.validity.validFrom ?? undefined,\n validUntil: query.validUntil ?? existing.validity.validUntil ?? undefined,\n volatile: query.volatile ?? existing.validity.volatile,\n operationMode: \"update\",\n targetPremiseId: query.premiseId,\n ...(context.scopeType && context.scopeId ? { scopeType: context.scopeType, scopeId: context.scopeId } : {}),\n });\n\n if (result.error) {\n return error(result.error);\n }\n\n if (!result.premise) {\n return error(\"Premise update failed — no updated premise returned.\");\n }\n\n const updated = result.premise;\n\n const updateResult = success({\n id: updated.id,\n assertion: updated.assertion.text,\n tier: updated.assertion.tier,\n status: updated.status,\n message: \"Premise updated successfully.\",\n });\n return updateResult;\n },\n });\n\n const retractPremise = defineTool({\n name: \"retract_premise\",\n description:\n \"Retracts a premise — a soft delete that preserves the history of what was asserted. \" +\n \"Retracted premises are no longer active but remain in the audit trail. \" +\n \"Use when the user explicitly wants to remove something they previously stated about themselves, \" +\n \"or when a contextual premise is no longer true.\\n\\n\" +\n \"**When to use:** When the user says 'remove my premise about...', 'I no longer...', \" +\n \"or 'that's not true anymore'. Do not retract premises proactively — only on explicit user instruction.\",\n querySchema: z.object({\n premiseId: z.string().describe(\"UUID of the premise to retract. Get from read_premises.\"),\n }),\n handler: async ({ context, query }) => {\n if (!UUID_REGEX.test(query.premiseId)) {\n return error(\"Invalid premiseId format.\");\n }\n\n const existing = await database.getPremise(query.premiseId);\n if (!existing) {\n return error(\"Premise not found.\");\n }\n if (existing.userId !== context.userId) {\n return error(\"You can only retract your own premises.\");\n }\n if (existing.status === \"RETRACTED\") {\n return error(\"Premise is already retracted.\");\n }\n\n retractPremiseLog.verbose('Retracting premise for user', { premiseId: query.premiseId, userId: context.userId });\n\n await database.updatePremise(query.premiseId, {\n status: \"RETRACTED\",\n retractedAt: new Date(),\n });\n\n const retractResult = success({\n id: query.premiseId,\n message: \"Premise retracted successfully.\",\n });\n return retractResult;\n },\n });\n\n return [createPremise, readPremises, updatePremise, retractPremise];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"questioner.ask.tool.d.ts","sourceRoot":"/","sources":["questioner/questioner.ask.tool.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAM5E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAsCxD,8EAA8E;AAC9E,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAEhF;AAqCD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,kBAsMhF"}
1
+ {"version":3,"file":"questioner.ask.tool.d.ts","sourceRoot":"/","sources":["questioner/questioner.ask.tool.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAM5E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AA8BxD,8EAA8E;AAC9E,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAEhF;AAqCD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,kBAsMhF"}
@@ -29,9 +29,8 @@ import { error, success } from "../shared/agent/tool.helpers.js";
29
29
  import { requestContext } from "../shared/observability/request-context.js";
30
30
  import { protocolLogger } from "../shared/observability/protocol.logger.js";
31
31
  import { QuestionerAgent } from "./questioner.agent.js";
32
+ import { chatQuestionWaitTimeoutMs } from "./questioner.env.js";
32
33
  const logger = protocolLogger("AskUserQuestionTool");
33
- /** Default in-tool wait budget for the user's answer (4 minutes). */
34
- const DEFAULT_WAIT_TIMEOUT_MS = 4 * 60 * 1000;
35
34
  /** Heartbeat interval while blocked, so SSE transports do not idle out. */
36
35
  const WAIT_HEARTBEAT_MS = 15000;
37
36
  /** Messages included in the conversation excerpt fed to the QuestionerAgent. */
@@ -44,13 +43,6 @@ const EXCERPT_MESSAGE_COUNT = 10;
44
43
  const EXCERPT_FETCH_LIMIT = 100;
45
44
  /** Max characters per message inside the excerpt. */
46
45
  const EXCERPT_MESSAGE_CHARS = 400;
47
- function waitTimeoutMs() {
48
- const raw = process.env.CHAT_QUESTION_WAIT_TIMEOUT_MS;
49
- if (!raw)
50
- return DEFAULT_WAIT_TIMEOUT_MS;
51
- const parsed = Number.parseInt(raw, 10);
52
- return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_WAIT_TIMEOUT_MS;
53
- }
54
46
  // Lazy singleton — construction binds the LLM once; invocations are stateless.
55
47
  let questionerAgent = null;
56
48
  function getQuestionerAgent() {
@@ -242,7 +234,7 @@ export function createAskUserQuestionTools(defineTool, deps) {
242
234
  }, WAIT_HEARTBEAT_MS);
243
235
  let outcomes;
244
236
  try {
245
- outcomes = await host.awaitAnswers(persisted.map((q) => q.id), { timeoutMs: waitTimeoutMs(), ...(signal ? { signal } : {}) });
237
+ outcomes = await host.awaitAnswers(persisted.map((q) => q.id), { timeoutMs: chatQuestionWaitTimeoutMs(), ...(signal ? { signal } : {}) });
246
238
  }
247
239
  finally {
248
240
  clearInterval(heartbeat);
@@ -1 +1 @@
1
- {"version":3,"file":"questioner.ask.tool.js","sourceRoot":"/","sources":["questioner/questioner.ask.tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ask_user_question — blocking mid-conversation questions for the chat\n * orchestrator (AskUserQuestion-style human-in-the-loop).\n *\n * Flow (hybrid authoring):\n * 1. The orchestrator states what it needs to learn (`purpose`) plus optional\n * draft questions.\n * 2. The QuestionerAgent (mode `chat`) refines that into polished structured\n * questions, grounded in the recent conversation excerpt and the user's\n * global context.\n * 3. Questions are persisted (`questions` table, mode `chat`,\n * `conversationId = sessionId`) via the injected {@link ChatQuestionsHost}.\n * 4. A `user_question` trace event streams the persisted questions to the\n * frontend, which renders them inline while the turn stays open.\n * 5. The tool blocks on `awaitAnswers` until the user answers/dismisses\n * through the questions REST endpoints, the wait budget elapses, or the\n * run is aborted. Answers come back as the tool result so the model\n * continues the SAME turn.\n *\n * On timeout the questions remain `pending`: they survive reloads via the\n * conversation-linked question fetch, and a later answer re-enters the chat\n * as a new user turn (frontend responsibility).\n *\n * Chat-only: not registered in the MCP tool registry. The handler also fails\n * gracefully when the session/stream context or host bridge is missing.\n */\nimport { z } from \"zod\";\n\nimport type { DefineTool, ToolDeps } from \"../shared/agent/tool.helpers.js\";\nimport { error, success } from \"../shared/agent/tool.helpers.js\";\nimport { requestContext } from \"../shared/observability/request-context.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport type { PersistableQuestion, PersistedQuestion, ChatQuestionAnswerOutcome } from \"../shared/interfaces/questioner.interface.js\";\nimport type { Question, QuestionStrategy } from \"../shared/schemas/question.schema.js\";\nimport { QuestionerAgent } from \"./questioner.agent.js\";\nimport type { ChatContext } from \"./questioner.types.js\";\n\nconst logger = protocolLogger(\"AskUserQuestionTool\");\n\n/** Default in-tool wait budget for the user's answer (4 minutes). */\nconst DEFAULT_WAIT_TIMEOUT_MS = 4 * 60 * 1000;\n\n/** Heartbeat interval while blocked, so SSE transports do not idle out. */\nconst WAIT_HEARTBEAT_MS = 15_000;\n\n/** Messages included in the conversation excerpt fed to the QuestionerAgent. */\nconst EXCERPT_MESSAGE_COUNT = 10;\n\n/**\n * Fetch window for the excerpt. Host adapters return the FIRST N messages\n * (ascending) when a limit is passed, so we fetch a wide window and keep the\n * tail to get the most recent exchange.\n */\nconst EXCERPT_FETCH_LIMIT = 100;\n\n/** Max characters per message inside the excerpt. */\nconst EXCERPT_MESSAGE_CHARS = 400;\n\nfunction waitTimeoutMs(): number {\n const raw = process.env.CHAT_QUESTION_WAIT_TIMEOUT_MS;\n if (!raw) return DEFAULT_WAIT_TIMEOUT_MS;\n const parsed = Number.parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_WAIT_TIMEOUT_MS;\n}\n\n// Lazy singleton — construction binds the LLM once; invocations are stateless.\nlet questionerAgent: QuestionerAgent | null = null;\nfunction getQuestionerAgent(): QuestionerAgent {\n if (!questionerAgent) questionerAgent = new QuestionerAgent();\n return questionerAgent;\n}\n\n/** Test seam: replace or reset the module-level QuestionerAgent singleton. */\nexport function setQuestionerAgentForTesting(agent: QuestionerAgent | null): void {\n questionerAgent = agent;\n}\n\nconst draftQuestionSchema = z.object({\n prompt: z\n .string()\n .min(5)\n .max(400)\n .describe(\"The question to ask, ending in a question mark. Self-contained plain language.\"),\n options: z\n .array(z.string().min(1).max(120))\n .min(2)\n .max(4)\n .optional()\n .describe(\"2-4 mutually distinct answer options. Omit to let the question generator derive them.\"),\n multiSelect: z\n .boolean()\n .optional()\n .describe(\"True when several options can be picked together (priorities, bundles).\"),\n});\n\n/**\n * Build a fallback Question directly from an orchestrator draft when the\n * QuestionerAgent produced nothing. Requires the draft to carry options.\n */\nfunction questionFromDraft(draft: z.infer<typeof draftQuestionSchema>, index: number): Question | null {\n if (!draft.options || draft.options.length < 2) return null;\n return {\n title: `Question ${index + 1}`,\n prompt: draft.prompt.slice(0, 400),\n options: draft.options.slice(0, 4).map((label) => ({\n label: label.slice(0, 120),\n description: label.slice(0, 280),\n })),\n multiSelect: draft.multiSelect ?? false,\n };\n}\n\n/**\n * Creates the chat-only `ask_user_question` tool. Registered by\n * `createChatTools` only when `deps.chatQuestions` is provided — never part\n * of the MCP tool registry (MCP clients have their own elicitation surface).\n *\n * @param defineTool - Tool factory provided by the composition root.\n * @param deps - Shared tool dependencies; requires `chatQuestions`.\n */\nexport function createAskUserQuestionTools(defineTool: DefineTool, deps: ToolDeps) {\n const askUserQuestion = defineTool({\n name: \"ask_user_question\",\n description:\n \"Ask the user 1-3 structured clarifying questions and WAIT for their answer before continuing. \" +\n \"The conversation pauses: the user sees interactive question cards inline and your turn resumes \" +\n \"with their selections as the tool result.\\n\\n\" +\n \"**Use when** a decision materially changes what you do next — before an expensive operation \" +\n \"(discovery, creating an intent from ambiguous input), when facing meaningfully different \" +\n \"directions, or when one concrete missing detail (timing, scope, budget, format) blocks progress.\\n\\n\" +\n \"**Do not use** for facts already visible in the conversation or profile, procedural \" +\n \"confirmations (\\\"Should I proceed?\\\"), or open-ended questions better asked in your response text.\\n\\n\" +\n \"**Input:** `purpose` states what you need to learn and why. Optionally propose `questions` \" +\n \"drafts (prompt + 2-4 options); a question generator refines wording and option quality.\\n\\n\" +\n \"**Returns:** One entry per question with `status` (`answered`/`dismissed`/`timeout`) and the \" +\n \"user's `selectedOptions`/`freeText`. On `timeout` the questions stay visible in the \" +\n \"conversation — acknowledge briefly and end your turn; do NOT repeat the questions in text.\",\n querySchema: z.object({\n purpose: z\n .string()\n .min(10)\n .max(600)\n .describe(\"What you need to learn from the user and why it changes what you do next.\"),\n questions: z\n .array(draftQuestionSchema)\n .min(1)\n .max(3)\n .optional()\n .describe(\"Draft questions to ask. The question generator polishes them before display.\"),\n }),\n handler: async ({ context, query }) => {\n const host = deps.chatQuestions;\n if (!host) {\n return error(\n \"Interactive questions are not available in this environment. Ask the user directly in your response text instead.\",\n );\n }\n if (context.isMcp || !context.sessionId) {\n return error(\n \"Interactive questions require a live chat session. Ask the user directly in your response text instead.\",\n );\n }\n const store = requestContext.getStore();\n const emit = store?.traceEmitter;\n const signal = store?.abortSignal;\n if (!emit) {\n return error(\n \"Interactive questions require a streaming chat turn. Ask the user directly in your response text instead.\",\n );\n }\n\n const sessionId = context.sessionId;\n\n // ── 1. Gather grounding context ────────────────────────────────────\n const [conversationExcerpt, userContext] = await Promise.all([\n loadConversationExcerpt(deps, sessionId),\n deps.getUserContextText?.(context.userId).catch(() => \"\") ?? Promise.resolve(\"\"),\n ]);\n\n // ── 2. Generate polished questions (hybrid: drafts + QuestionerAgent) ──\n const chatContext: ChatContext = {\n purpose: query.purpose,\n ...(query.questions?.length ? { draftQuestions: query.questions } : {}),\n ...(conversationExcerpt ? { conversationExcerpt } : {}),\n ...(userContext ? { userContext } : {}),\n };\n\n let generated: { questions: Question[]; strategies: QuestionStrategy[] } | null = null;\n try {\n generated = await getQuestionerAgent().invoke(\n {\n mode: \"chat\",\n userId: context.userId,\n sourceType: \"conversation\",\n sourceId: sessionId,\n context: chatContext,\n conversationId: sessionId,\n },\n signal ? { signal } : undefined,\n );\n } catch (err) {\n logger.warn(\"QuestionerAgent invocation failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n let finalQuestions: Question[];\n let strategies: QuestionStrategy[];\n if (generated && generated.questions.length > 0) {\n finalQuestions = generated.questions;\n strategies = generated.strategies;\n } else {\n // Fallback: use the orchestrator's own drafts verbatim (options required).\n const fromDrafts = (query.questions ?? [])\n .map((d, i) => questionFromDraft(d, i))\n .filter((q): q is Question => q !== null);\n if (fromDrafts.length === 0) {\n return error(\n \"Could not prepare structured questions. Ask the user directly in your response text instead.\",\n );\n }\n finalQuestions = fromDrafts;\n strategies = fromDrafts.map(() => \"surface_missing_detail\" as const);\n }\n\n if (signal?.aborted) {\n return error(\"The chat turn was cancelled before the questions could be shown.\");\n }\n\n // ── 3. Persist (mode `chat`, linked to this conversation) ──────────\n const timestamp = new Date().toISOString();\n const batch: PersistableQuestion[] = finalQuestions.map((payload, i) => ({\n detection: {\n mode: \"chat\",\n sourceType: \"conversation\",\n sourceId: sessionId,\n timestamp,\n },\n actors: [{ userId: context.userId, role: \"subject\" as const }],\n payload,\n strategy: strategies[i] ?? \"surface_missing_detail\",\n conversationId: sessionId,\n }));\n\n let persisted: PersistedQuestion[];\n try {\n persisted = await host.persist(batch);\n } catch (err) {\n logger.error(\"Failed to persist chat questions\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return error(\"Could not deliver the questions to the user. Ask directly in your response text instead.\");\n }\n\n // ── 4. Stream the cards to the frontend ────────────────────────────\n emit({\n type: \"user_question\",\n questions: persisted.map((q) => ({\n id: q.id,\n title: q.payload.title,\n prompt: q.payload.prompt,\n options: q.payload.options,\n multiSelect: q.payload.multiSelect,\n })),\n });\n\n // ── 5. Block until answered / dismissed / timeout / abort ──────────\n const heartbeat = setInterval(() => {\n try {\n emit({ type: \"status\", message: \"Waiting for your answer…\" });\n } catch {\n /* stream may be closing; the wait resolves via timeout/abort */\n }\n }, WAIT_HEARTBEAT_MS);\n\n let outcomes: ChatQuestionAnswerOutcome[];\n try {\n outcomes = await host.awaitAnswers(\n persisted.map((q) => q.id),\n { timeoutMs: waitTimeoutMs(), ...(signal ? { signal } : {}) },\n );\n } finally {\n clearInterval(heartbeat);\n }\n\n const byId = new Map(persisted.map((q) => [q.id, q]));\n const results = outcomes.map((o) => {\n const q = byId.get(o.questionId);\n return {\n questionId: o.questionId,\n prompt: q?.payload.prompt ?? \"\",\n status: o.status,\n ...(o.answer\n ? {\n selectedOptions: o.answer.selectedOptions,\n ...(o.answer.freeText ? { freeText: o.answer.freeText } : {}),\n }\n : {}),\n };\n });\n\n const answeredCount = results.filter((r) => r.status === \"answered\").length;\n const timedOut = results.some((r) => r.status === \"timeout\");\n\n return success({\n answers: results,\n summary: `${answeredCount} of ${results.length} question(s) answered`,\n ...(timedOut\n ? {\n guidance:\n \"The user has not answered the remaining question(s) yet. They stay visible in the conversation — acknowledge briefly, do NOT repeat the questions in text, and end your turn.\",\n }\n : {}),\n });\n },\n });\n\n return [askUserQuestion] as const;\n}\n\n/**\n * Load a compact excerpt of the most recent conversation messages for the\n * QuestionerAgent's grounding. Best-effort: returns \"\" on any failure or when\n * no chat session reader is available. Note: the in-flight user message is\n * not yet persisted; the orchestrator's `purpose` carries that context.\n */\nasync function loadConversationExcerpt(deps: ToolDeps, sessionId: string): Promise<string> {\n if (!deps.chatSession) return \"\";\n try {\n const messages = await deps.chatSession.getSessionMessages(sessionId, EXCERPT_FETCH_LIMIT);\n if (!messages || messages.length === 0) return \"\";\n return messages\n .slice(-EXCERPT_MESSAGE_COUNT)\n .map((m) => {\n const role = m.role === \"assistant\" ? \"Assistant\" : \"User\";\n const text = (m.content ?? \"\").replace(/\\s+/g, \" \").trim();\n return `${role}: ${text.slice(0, EXCERPT_MESSAGE_CHARS)}`;\n })\n .join(\"\\n\");\n } catch (err) {\n logger.warn(\"Failed to load conversation excerpt\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return \"\";\n }\n}\n"]}
1
+ {"version":3,"file":"questioner.ask.tool.js","sourceRoot":"/","sources":["questioner/questioner.ask.tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ask_user_question — blocking mid-conversation questions for the chat\n * orchestrator (AskUserQuestion-style human-in-the-loop).\n *\n * Flow (hybrid authoring):\n * 1. The orchestrator states what it needs to learn (`purpose`) plus optional\n * draft questions.\n * 2. The QuestionerAgent (mode `chat`) refines that into polished structured\n * questions, grounded in the recent conversation excerpt and the user's\n * global context.\n * 3. Questions are persisted (`questions` table, mode `chat`,\n * `conversationId = sessionId`) via the injected {@link ChatQuestionsHost}.\n * 4. A `user_question` trace event streams the persisted questions to the\n * frontend, which renders them inline while the turn stays open.\n * 5. The tool blocks on `awaitAnswers` until the user answers/dismisses\n * through the questions REST endpoints, the wait budget elapses, or the\n * run is aborted. Answers come back as the tool result so the model\n * continues the SAME turn.\n *\n * On timeout the questions remain `pending`: they survive reloads via the\n * conversation-linked question fetch, and a later answer re-enters the chat\n * as a new user turn (frontend responsibility).\n *\n * Chat-only: not registered in the MCP tool registry. The handler also fails\n * gracefully when the session/stream context or host bridge is missing.\n */\nimport { z } from \"zod\";\n\nimport type { DefineTool, ToolDeps } from \"../shared/agent/tool.helpers.js\";\nimport { error, success } from \"../shared/agent/tool.helpers.js\";\nimport { requestContext } from \"../shared/observability/request-context.js\";\nimport { protocolLogger } from \"../shared/observability/protocol.logger.js\";\nimport type { PersistableQuestion, PersistedQuestion, ChatQuestionAnswerOutcome } from \"../shared/interfaces/questioner.interface.js\";\nimport type { Question, QuestionStrategy } from \"../shared/schemas/question.schema.js\";\nimport { QuestionerAgent } from \"./questioner.agent.js\";\nimport { chatQuestionWaitTimeoutMs } from \"./questioner.env.js\";\nimport type { ChatContext } from \"./questioner.types.js\";\n\nconst logger = protocolLogger(\"AskUserQuestionTool\");\n\n\n/** Heartbeat interval while blocked, so SSE transports do not idle out. */\nconst WAIT_HEARTBEAT_MS = 15_000;\n\n/** Messages included in the conversation excerpt fed to the QuestionerAgent. */\nconst EXCERPT_MESSAGE_COUNT = 10;\n\n/**\n * Fetch window for the excerpt. Host adapters return the FIRST N messages\n * (ascending) when a limit is passed, so we fetch a wide window and keep the\n * tail to get the most recent exchange.\n */\nconst EXCERPT_FETCH_LIMIT = 100;\n\n/** Max characters per message inside the excerpt. */\nconst EXCERPT_MESSAGE_CHARS = 400;\n\n// Lazy singleton — construction binds the LLM once; invocations are stateless.\nlet questionerAgent: QuestionerAgent | null = null;\nfunction getQuestionerAgent(): QuestionerAgent {\n if (!questionerAgent) questionerAgent = new QuestionerAgent();\n return questionerAgent;\n}\n\n/** Test seam: replace or reset the module-level QuestionerAgent singleton. */\nexport function setQuestionerAgentForTesting(agent: QuestionerAgent | null): void {\n questionerAgent = agent;\n}\n\nconst draftQuestionSchema = z.object({\n prompt: z\n .string()\n .min(5)\n .max(400)\n .describe(\"The question to ask, ending in a question mark. Self-contained plain language.\"),\n options: z\n .array(z.string().min(1).max(120))\n .min(2)\n .max(4)\n .optional()\n .describe(\"2-4 mutually distinct answer options. Omit to let the question generator derive them.\"),\n multiSelect: z\n .boolean()\n .optional()\n .describe(\"True when several options can be picked together (priorities, bundles).\"),\n});\n\n/**\n * Build a fallback Question directly from an orchestrator draft when the\n * QuestionerAgent produced nothing. Requires the draft to carry options.\n */\nfunction questionFromDraft(draft: z.infer<typeof draftQuestionSchema>, index: number): Question | null {\n if (!draft.options || draft.options.length < 2) return null;\n return {\n title: `Question ${index + 1}`,\n prompt: draft.prompt.slice(0, 400),\n options: draft.options.slice(0, 4).map((label) => ({\n label: label.slice(0, 120),\n description: label.slice(0, 280),\n })),\n multiSelect: draft.multiSelect ?? false,\n };\n}\n\n/**\n * Creates the chat-only `ask_user_question` tool. Registered by\n * `createChatTools` only when `deps.chatQuestions` is provided — never part\n * of the MCP tool registry (MCP clients have their own elicitation surface).\n *\n * @param defineTool - Tool factory provided by the composition root.\n * @param deps - Shared tool dependencies; requires `chatQuestions`.\n */\nexport function createAskUserQuestionTools(defineTool: DefineTool, deps: ToolDeps) {\n const askUserQuestion = defineTool({\n name: \"ask_user_question\",\n description:\n \"Ask the user 1-3 structured clarifying questions and WAIT for their answer before continuing. \" +\n \"The conversation pauses: the user sees interactive question cards inline and your turn resumes \" +\n \"with their selections as the tool result.\\n\\n\" +\n \"**Use when** a decision materially changes what you do next — before an expensive operation \" +\n \"(discovery, creating an intent from ambiguous input), when facing meaningfully different \" +\n \"directions, or when one concrete missing detail (timing, scope, budget, format) blocks progress.\\n\\n\" +\n \"**Do not use** for facts already visible in the conversation or profile, procedural \" +\n \"confirmations (\\\"Should I proceed?\\\"), or open-ended questions better asked in your response text.\\n\\n\" +\n \"**Input:** `purpose` states what you need to learn and why. Optionally propose `questions` \" +\n \"drafts (prompt + 2-4 options); a question generator refines wording and option quality.\\n\\n\" +\n \"**Returns:** One entry per question with `status` (`answered`/`dismissed`/`timeout`) and the \" +\n \"user's `selectedOptions`/`freeText`. On `timeout` the questions stay visible in the \" +\n \"conversation — acknowledge briefly and end your turn; do NOT repeat the questions in text.\",\n querySchema: z.object({\n purpose: z\n .string()\n .min(10)\n .max(600)\n .describe(\"What you need to learn from the user and why it changes what you do next.\"),\n questions: z\n .array(draftQuestionSchema)\n .min(1)\n .max(3)\n .optional()\n .describe(\"Draft questions to ask. The question generator polishes them before display.\"),\n }),\n handler: async ({ context, query }) => {\n const host = deps.chatQuestions;\n if (!host) {\n return error(\n \"Interactive questions are not available in this environment. Ask the user directly in your response text instead.\",\n );\n }\n if (context.isMcp || !context.sessionId) {\n return error(\n \"Interactive questions require a live chat session. Ask the user directly in your response text instead.\",\n );\n }\n const store = requestContext.getStore();\n const emit = store?.traceEmitter;\n const signal = store?.abortSignal;\n if (!emit) {\n return error(\n \"Interactive questions require a streaming chat turn. Ask the user directly in your response text instead.\",\n );\n }\n\n const sessionId = context.sessionId;\n\n // ── 1. Gather grounding context ────────────────────────────────────\n const [conversationExcerpt, userContext] = await Promise.all([\n loadConversationExcerpt(deps, sessionId),\n deps.getUserContextText?.(context.userId).catch(() => \"\") ?? Promise.resolve(\"\"),\n ]);\n\n // ── 2. Generate polished questions (hybrid: drafts + QuestionerAgent) ──\n const chatContext: ChatContext = {\n purpose: query.purpose,\n ...(query.questions?.length ? { draftQuestions: query.questions } : {}),\n ...(conversationExcerpt ? { conversationExcerpt } : {}),\n ...(userContext ? { userContext } : {}),\n };\n\n let generated: { questions: Question[]; strategies: QuestionStrategy[] } | null = null;\n try {\n generated = await getQuestionerAgent().invoke(\n {\n mode: \"chat\",\n userId: context.userId,\n sourceType: \"conversation\",\n sourceId: sessionId,\n context: chatContext,\n conversationId: sessionId,\n },\n signal ? { signal } : undefined,\n );\n } catch (err) {\n logger.warn(\"QuestionerAgent invocation failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n let finalQuestions: Question[];\n let strategies: QuestionStrategy[];\n if (generated && generated.questions.length > 0) {\n finalQuestions = generated.questions;\n strategies = generated.strategies;\n } else {\n // Fallback: use the orchestrator's own drafts verbatim (options required).\n const fromDrafts = (query.questions ?? [])\n .map((d, i) => questionFromDraft(d, i))\n .filter((q): q is Question => q !== null);\n if (fromDrafts.length === 0) {\n return error(\n \"Could not prepare structured questions. Ask the user directly in your response text instead.\",\n );\n }\n finalQuestions = fromDrafts;\n strategies = fromDrafts.map(() => \"surface_missing_detail\" as const);\n }\n\n if (signal?.aborted) {\n return error(\"The chat turn was cancelled before the questions could be shown.\");\n }\n\n // ── 3. Persist (mode `chat`, linked to this conversation) ──────────\n const timestamp = new Date().toISOString();\n const batch: PersistableQuestion[] = finalQuestions.map((payload, i) => ({\n detection: {\n mode: \"chat\",\n sourceType: \"conversation\",\n sourceId: sessionId,\n timestamp,\n },\n actors: [{ userId: context.userId, role: \"subject\" as const }],\n payload,\n strategy: strategies[i] ?? \"surface_missing_detail\",\n conversationId: sessionId,\n }));\n\n let persisted: PersistedQuestion[];\n try {\n persisted = await host.persist(batch);\n } catch (err) {\n logger.error(\"Failed to persist chat questions\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return error(\"Could not deliver the questions to the user. Ask directly in your response text instead.\");\n }\n\n // ── 4. Stream the cards to the frontend ────────────────────────────\n emit({\n type: \"user_question\",\n questions: persisted.map((q) => ({\n id: q.id,\n title: q.payload.title,\n prompt: q.payload.prompt,\n options: q.payload.options,\n multiSelect: q.payload.multiSelect,\n })),\n });\n\n // ── 5. Block until answered / dismissed / timeout / abort ──────────\n const heartbeat = setInterval(() => {\n try {\n emit({ type: \"status\", message: \"Waiting for your answer…\" });\n } catch {\n /* stream may be closing; the wait resolves via timeout/abort */\n }\n }, WAIT_HEARTBEAT_MS);\n\n let outcomes: ChatQuestionAnswerOutcome[];\n try {\n outcomes = await host.awaitAnswers(\n persisted.map((q) => q.id),\n { timeoutMs: chatQuestionWaitTimeoutMs(), ...(signal ? { signal } : {}) },\n );\n } finally {\n clearInterval(heartbeat);\n }\n\n const byId = new Map(persisted.map((q) => [q.id, q]));\n const results = outcomes.map((o) => {\n const q = byId.get(o.questionId);\n return {\n questionId: o.questionId,\n prompt: q?.payload.prompt ?? \"\",\n status: o.status,\n ...(o.answer\n ? {\n selectedOptions: o.answer.selectedOptions,\n ...(o.answer.freeText ? { freeText: o.answer.freeText } : {}),\n }\n : {}),\n };\n });\n\n const answeredCount = results.filter((r) => r.status === \"answered\").length;\n const timedOut = results.some((r) => r.status === \"timeout\");\n\n return success({\n answers: results,\n summary: `${answeredCount} of ${results.length} question(s) answered`,\n ...(timedOut\n ? {\n guidance:\n \"The user has not answered the remaining question(s) yet. They stay visible in the conversation — acknowledge briefly, do NOT repeat the questions in text, and end your turn.\",\n }\n : {}),\n });\n },\n });\n\n return [askUserQuestion] as const;\n}\n\n/**\n * Load a compact excerpt of the most recent conversation messages for the\n * QuestionerAgent's grounding. Best-effort: returns \"\" on any failure or when\n * no chat session reader is available. Note: the in-flight user message is\n * not yet persisted; the orchestrator's `purpose` carries that context.\n */\nasync function loadConversationExcerpt(deps: ToolDeps, sessionId: string): Promise<string> {\n if (!deps.chatSession) return \"\";\n try {\n const messages = await deps.chatSession.getSessionMessages(sessionId, EXCERPT_FETCH_LIMIT);\n if (!messages || messages.length === 0) return \"\";\n return messages\n .slice(-EXCERPT_MESSAGE_COUNT)\n .map((m) => {\n const role = m.role === \"assistant\" ? \"Assistant\" : \"User\";\n const text = (m.content ?? \"\").replace(/\\s+/g, \" \").trim();\n return `${role}: ${text.slice(0, EXCERPT_MESSAGE_CHARS)}`;\n })\n .join(\"\\n\");\n } catch (err) {\n logger.warn(\"Failed to load conversation excerpt\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return \"\";\n }\n}\n"]}