@carlonicora/nestjs-neo4jsonapi 1.64.0 → 1.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/dist/agents/agents.modules.js +3 -3
  2. package/dist/agents/agents.modules.js.map +1 -1
  3. package/dist/agents/graph/graph.module.d.ts +3 -0
  4. package/dist/agents/graph/graph.module.d.ts.map +1 -0
  5. package/dist/agents/{chatbot/chatbot.module.js → graph/graph.module.js} +12 -16
  6. package/dist/agents/graph/graph.module.js.map +1 -0
  7. package/dist/agents/{chatbot → graph}/interfaces/graph.catalog.interface.d.ts +4 -0
  8. package/dist/agents/graph/interfaces/graph.catalog.interface.d.ts.map +1 -0
  9. package/dist/agents/graph/interfaces/graph.catalog.interface.js.map +1 -0
  10. package/dist/agents/graph/interfaces/graph.node.output.interface.d.ts +30 -0
  11. package/dist/agents/graph/interfaces/graph.node.output.interface.d.ts.map +1 -0
  12. package/dist/agents/graph/interfaces/graph.node.output.interface.js +3 -0
  13. package/dist/agents/graph/interfaces/graph.node.output.interface.js.map +1 -0
  14. package/dist/agents/graph/prompts/graph.node.system.prompt.d.ts +3 -0
  15. package/dist/agents/graph/prompts/graph.node.system.prompt.d.ts.map +1 -0
  16. package/dist/agents/graph/prompts/graph.node.system.prompt.js +66 -0
  17. package/dist/agents/graph/prompts/graph.node.system.prompt.js.map +1 -0
  18. package/dist/agents/graph/repositories/user-modules.repository.d.ts.map +1 -0
  19. package/dist/agents/graph/repositories/user-modules.repository.js.map +1 -0
  20. package/dist/agents/{chatbot → graph}/services/descriptor.source.d.ts +2 -0
  21. package/dist/agents/graph/services/descriptor.source.d.ts.map +1 -0
  22. package/dist/agents/{chatbot → graph}/services/descriptor.source.js +18 -3
  23. package/dist/agents/graph/services/descriptor.source.js.map +1 -0
  24. package/dist/agents/graph/services/field-formatting.d.ts.map +1 -0
  25. package/dist/agents/graph/services/field-formatting.js.map +1 -0
  26. package/dist/agents/{chatbot → graph}/services/graph.catalog.service.d.ts +16 -0
  27. package/dist/agents/graph/services/graph.catalog.service.d.ts.map +1 -0
  28. package/dist/agents/{chatbot → graph}/services/graph.catalog.service.js +63 -1
  29. package/dist/agents/graph/services/graph.catalog.service.js.map +1 -0
  30. package/dist/agents/{chatbot/services/chatbot.index.manager.d.ts → graph/services/graph.index.manager.d.ts} +2 -2
  31. package/dist/agents/graph/services/graph.index.manager.d.ts.map +1 -0
  32. package/dist/agents/{chatbot/services/chatbot.index.manager.js → graph/services/graph.index.manager.js} +9 -9
  33. package/dist/agents/graph/services/graph.index.manager.js.map +1 -0
  34. package/dist/agents/graph/services/graph.search.service.d.ts +69 -0
  35. package/dist/agents/graph/services/graph.search.service.d.ts.map +1 -0
  36. package/dist/agents/graph/services/graph.search.service.js +230 -0
  37. package/dist/agents/graph/services/graph.search.service.js.map +1 -0
  38. package/dist/agents/graph/services/humanize-tool.d.ts.map +1 -0
  39. package/dist/agents/graph/services/humanize-tool.js.map +1 -0
  40. package/dist/agents/graph/services/materialise-bridge.d.ts +36 -0
  41. package/dist/agents/graph/services/materialise-bridge.d.ts.map +1 -0
  42. package/dist/agents/graph/services/materialise-bridge.js +69 -0
  43. package/dist/agents/graph/services/materialise-bridge.js.map +1 -0
  44. package/dist/agents/graph/tools/describe-entity.tool.d.ts.map +1 -0
  45. package/dist/agents/{chatbot → graph}/tools/describe-entity.tool.js +1 -0
  46. package/dist/agents/graph/tools/describe-entity.tool.js.map +1 -0
  47. package/dist/agents/{chatbot → graph}/tools/read-entity.tool.d.ts +5 -1
  48. package/dist/agents/graph/tools/read-entity.tool.d.ts.map +1 -0
  49. package/dist/agents/{chatbot → graph}/tools/read-entity.tool.js +37 -8
  50. package/dist/agents/graph/tools/read-entity.tool.js.map +1 -0
  51. package/dist/agents/{chatbot → graph}/tools/resolve-entity.tool.d.ts +2 -2
  52. package/dist/agents/graph/tools/resolve-entity.tool.d.ts.map +1 -0
  53. package/dist/agents/{chatbot → graph}/tools/resolve-entity.tool.js +2 -2
  54. package/dist/agents/graph/tools/resolve-entity.tool.js.map +1 -0
  55. package/dist/agents/{chatbot → graph}/tools/search-entities.tool.d.ts +6 -2
  56. package/dist/agents/graph/tools/search-entities.tool.d.ts.map +1 -0
  57. package/dist/agents/{chatbot → graph}/tools/search-entities.tool.js +36 -12
  58. package/dist/agents/graph/tools/search-entities.tool.js.map +1 -0
  59. package/dist/agents/{chatbot → graph}/tools/tool.factory.d.ts +7 -0
  60. package/dist/agents/graph/tools/tool.factory.d.ts.map +1 -0
  61. package/dist/agents/{chatbot → graph}/tools/tool.factory.js +57 -3
  62. package/dist/agents/graph/tools/tool.factory.js.map +1 -0
  63. package/dist/agents/{chatbot → graph}/tools/traverse.tool.d.ts +5 -1
  64. package/dist/agents/graph/tools/traverse.tool.d.ts.map +1 -0
  65. package/dist/agents/{chatbot → graph}/tools/traverse.tool.js +38 -15
  66. package/dist/agents/graph/tools/traverse.tool.js.map +1 -0
  67. package/dist/agents/index.d.ts +6 -9
  68. package/dist/agents/index.d.ts.map +1 -1
  69. package/dist/agents/index.js +13 -15
  70. package/dist/agents/index.js.map +1 -1
  71. package/dist/agents/responder/contexts/responder.context.d.ts +75 -1
  72. package/dist/agents/responder/contexts/responder.context.d.ts.map +1 -1
  73. package/dist/agents/responder/contexts/responder.context.js +29 -4
  74. package/dist/agents/responder/contexts/responder.context.js.map +1 -1
  75. package/dist/agents/responder/factories/responder.context.factory.d.ts +4 -5
  76. package/dist/agents/responder/factories/responder.context.factory.d.ts.map +1 -1
  77. package/dist/agents/responder/factories/responder.context.factory.js +28 -8
  78. package/dist/agents/responder/factories/responder.context.factory.js.map +1 -1
  79. package/dist/agents/responder/interfaces/entity.reference.interface.d.ts +7 -0
  80. package/dist/agents/responder/interfaces/entity.reference.interface.d.ts.map +1 -0
  81. package/dist/agents/{chatbot/interfaces/chatbot.response.interface.js → responder/interfaces/entity.reference.interface.js} +1 -1
  82. package/dist/agents/responder/interfaces/entity.reference.interface.js.map +1 -0
  83. package/dist/agents/responder/interfaces/responder.response.interface.d.ts +12 -3
  84. package/dist/agents/responder/interfaces/responder.response.interface.d.ts.map +1 -1
  85. package/dist/agents/responder/interfaces/unified.trace.interface.d.ts +64 -0
  86. package/dist/agents/responder/interfaces/unified.trace.interface.d.ts.map +1 -0
  87. package/dist/agents/responder/interfaces/unified.trace.interface.js +3 -0
  88. package/dist/agents/responder/interfaces/unified.trace.interface.js.map +1 -0
  89. package/dist/agents/responder/nodes/graph.node.service.d.ts +31 -0
  90. package/dist/agents/responder/nodes/graph.node.service.d.ts.map +1 -0
  91. package/dist/agents/responder/nodes/graph.node.service.js +319 -0
  92. package/dist/agents/responder/nodes/graph.node.service.js.map +1 -0
  93. package/dist/agents/responder/nodes/planner.node.service.d.ts +14 -0
  94. package/dist/agents/responder/nodes/planner.node.service.d.ts.map +1 -0
  95. package/dist/agents/responder/nodes/planner.node.service.js +121 -0
  96. package/dist/agents/responder/nodes/planner.node.service.js.map +1 -0
  97. package/dist/agents/responder/nodes/responder.answer.node.service.d.ts +5 -23
  98. package/dist/agents/responder/nodes/responder.answer.node.service.d.ts.map +1 -1
  99. package/dist/agents/responder/nodes/responder.answer.node.service.js +257 -432
  100. package/dist/agents/responder/nodes/responder.answer.node.service.js.map +1 -1
  101. package/dist/agents/responder/responder.module.d.ts.map +1 -1
  102. package/dist/agents/responder/responder.module.js +12 -3
  103. package/dist/agents/responder/responder.module.js.map +1 -1
  104. package/dist/agents/responder/services/responder.service.d.ts +15 -22
  105. package/dist/agents/responder/services/responder.service.d.ts.map +1 -1
  106. package/dist/agents/responder/services/responder.service.js +116 -89
  107. package/dist/agents/responder/services/responder.service.js.map +1 -1
  108. package/dist/common/helpers/define-entity.d.ts.map +1 -1
  109. package/dist/common/helpers/define-entity.js +16 -1
  110. package/dist/common/helpers/define-entity.js.map +1 -1
  111. package/dist/common/interfaces/entity.schema.interface.d.ts +15 -0
  112. package/dist/common/interfaces/entity.schema.interface.d.ts.map +1 -1
  113. package/dist/core/llm/interfaces/llm-call-metadata.interface.d.ts +19 -0
  114. package/dist/core/llm/interfaces/llm-call-metadata.interface.d.ts.map +1 -0
  115. package/dist/core/llm/interfaces/llm-call-metadata.interface.js +3 -0
  116. package/dist/core/llm/interfaces/llm-call-metadata.interface.js.map +1 -0
  117. package/dist/core/llm/llm.module.d.ts +1 -0
  118. package/dist/core/llm/llm.module.d.ts.map +1 -1
  119. package/dist/core/llm/llm.module.js +3 -1
  120. package/dist/core/llm/llm.module.js.map +1 -1
  121. package/dist/core/llm/services/llm-call-dumper.service.d.ts +64 -0
  122. package/dist/core/llm/services/llm-call-dumper.service.d.ts.map +1 -0
  123. package/dist/core/llm/services/llm-call-dumper.service.js +204 -0
  124. package/dist/core/llm/services/llm-call-dumper.service.js.map +1 -0
  125. package/dist/core/llm/services/llm.service.d.ts +4 -1
  126. package/dist/core/llm/services/llm.service.d.ts.map +1 -1
  127. package/dist/core/llm/services/llm.service.js +304 -220
  128. package/dist/core/llm/services/llm.service.js.map +1 -1
  129. package/dist/foundations/assistant/assistant.module.d.ts.map +1 -1
  130. package/dist/foundations/assistant/assistant.module.js +3 -2
  131. package/dist/foundations/assistant/assistant.module.js.map +1 -1
  132. package/dist/foundations/assistant/entities/assistant.d.ts +15 -16
  133. package/dist/foundations/assistant/entities/assistant.d.ts.map +1 -1
  134. package/dist/foundations/assistant/entities/assistant.js +21 -9
  135. package/dist/foundations/assistant/entities/assistant.js.map +1 -1
  136. package/dist/foundations/assistant/repositories/assistant.repository.d.ts +13 -0
  137. package/dist/foundations/assistant/repositories/assistant.repository.d.ts.map +1 -1
  138. package/dist/foundations/assistant/services/assistant.service.d.ts +35 -10
  139. package/dist/foundations/assistant/services/assistant.service.d.ts.map +1 -1
  140. package/dist/foundations/assistant/services/assistant.service.js +132 -17
  141. package/dist/foundations/assistant/services/assistant.service.js.map +1 -1
  142. package/dist/foundations/assistant-message/entities/assistant-message.d.ts +30 -10
  143. package/dist/foundations/assistant-message/entities/assistant-message.d.ts.map +1 -1
  144. package/dist/foundations/assistant-message/entities/assistant-message.js +19 -4
  145. package/dist/foundations/assistant-message/entities/assistant-message.js.map +1 -1
  146. package/dist/foundations/assistant-message/repositories/assistant-message.repository.d.ts +53 -4
  147. package/dist/foundations/assistant-message/repositories/assistant-message.repository.d.ts.map +1 -1
  148. package/dist/foundations/assistant-message/repositories/assistant-message.repository.js +43 -3
  149. package/dist/foundations/assistant-message/repositories/assistant-message.repository.js.map +1 -1
  150. package/dist/foundations/assistant-message/services/assistant-message.service.d.ts +26 -0
  151. package/dist/foundations/assistant-message/services/assistant-message.service.d.ts.map +1 -1
  152. package/dist/foundations/chunk/chunk.module.d.ts.map +1 -1
  153. package/dist/foundations/chunk/chunk.module.js +4 -5
  154. package/dist/foundations/chunk/chunk.module.js.map +1 -1
  155. package/dist/foundations/chunk/entities/chunk.entity.d.ts +19 -4
  156. package/dist/foundations/chunk/entities/chunk.entity.d.ts.map +1 -1
  157. package/dist/foundations/chunk/entities/chunk.entity.js +48 -0
  158. package/dist/foundations/chunk/entities/chunk.entity.js.map +1 -1
  159. package/dist/foundations/chunk/index.d.ts +1 -2
  160. package/dist/foundations/chunk/index.d.ts.map +1 -1
  161. package/dist/foundations/chunk/index.js +3 -3
  162. package/dist/foundations/chunk/index.js.map +1 -1
  163. package/dist/foundations/chunk/repositories/chunk.repository.d.ts.map +1 -1
  164. package/dist/foundations/chunk/repositories/chunk.repository.js +8 -8
  165. package/dist/foundations/chunk/repositories/chunk.repository.js.map +1 -1
  166. package/dist/foundations/chunk/services/chunk.service.d.ts.map +1 -1
  167. package/dist/foundations/chunk/services/chunk.service.js +2 -2
  168. package/dist/foundations/chunk/services/chunk.service.js.map +1 -1
  169. package/package.json +1 -1
  170. package/dist/agents/chatbot/chatbot.module.d.ts +0 -3
  171. package/dist/agents/chatbot/chatbot.module.d.ts.map +0 -1
  172. package/dist/agents/chatbot/chatbot.module.js.map +0 -1
  173. package/dist/agents/chatbot/interfaces/chatbot.response.interface.d.ts +0 -25
  174. package/dist/agents/chatbot/interfaces/chatbot.response.interface.d.ts.map +0 -1
  175. package/dist/agents/chatbot/interfaces/chatbot.response.interface.js.map +0 -1
  176. package/dist/agents/chatbot/interfaces/graph.catalog.interface.d.ts.map +0 -1
  177. package/dist/agents/chatbot/interfaces/graph.catalog.interface.js.map +0 -1
  178. package/dist/agents/chatbot/prompts/chatbot.system.prompt.d.ts +0 -3
  179. package/dist/agents/chatbot/prompts/chatbot.system.prompt.d.ts.map +0 -1
  180. package/dist/agents/chatbot/prompts/chatbot.system.prompt.js +0 -60
  181. package/dist/agents/chatbot/prompts/chatbot.system.prompt.js.map +0 -1
  182. package/dist/agents/chatbot/repositories/user-modules.repository.d.ts.map +0 -1
  183. package/dist/agents/chatbot/repositories/user-modules.repository.js.map +0 -1
  184. package/dist/agents/chatbot/services/chatbot.index.manager.d.ts.map +0 -1
  185. package/dist/agents/chatbot/services/chatbot.index.manager.js.map +0 -1
  186. package/dist/agents/chatbot/services/chatbot.search.service.d.ts +0 -46
  187. package/dist/agents/chatbot/services/chatbot.search.service.d.ts.map +0 -1
  188. package/dist/agents/chatbot/services/chatbot.search.service.js +0 -148
  189. package/dist/agents/chatbot/services/chatbot.search.service.js.map +0 -1
  190. package/dist/agents/chatbot/services/chatbot.service.d.ts +0 -36
  191. package/dist/agents/chatbot/services/chatbot.service.d.ts.map +0 -1
  192. package/dist/agents/chatbot/services/chatbot.service.js +0 -220
  193. package/dist/agents/chatbot/services/chatbot.service.js.map +0 -1
  194. package/dist/agents/chatbot/services/descriptor.source.d.ts.map +0 -1
  195. package/dist/agents/chatbot/services/descriptor.source.js.map +0 -1
  196. package/dist/agents/chatbot/services/field-formatting.d.ts.map +0 -1
  197. package/dist/agents/chatbot/services/field-formatting.js.map +0 -1
  198. package/dist/agents/chatbot/services/graph.catalog.service.d.ts.map +0 -1
  199. package/dist/agents/chatbot/services/graph.catalog.service.js.map +0 -1
  200. package/dist/agents/chatbot/services/humanize-tool.d.ts.map +0 -1
  201. package/dist/agents/chatbot/services/humanize-tool.js.map +0 -1
  202. package/dist/agents/chatbot/tools/describe-entity.tool.d.ts.map +0 -1
  203. package/dist/agents/chatbot/tools/describe-entity.tool.js.map +0 -1
  204. package/dist/agents/chatbot/tools/read-entity.tool.d.ts.map +0 -1
  205. package/dist/agents/chatbot/tools/read-entity.tool.js.map +0 -1
  206. package/dist/agents/chatbot/tools/resolve-entity.tool.d.ts.map +0 -1
  207. package/dist/agents/chatbot/tools/resolve-entity.tool.js.map +0 -1
  208. package/dist/agents/chatbot/tools/search-entities.tool.d.ts.map +0 -1
  209. package/dist/agents/chatbot/tools/search-entities.tool.js.map +0 -1
  210. package/dist/agents/chatbot/tools/tool.factory.d.ts.map +0 -1
  211. package/dist/agents/chatbot/tools/tool.factory.js.map +0 -1
  212. package/dist/agents/chatbot/tools/traverse.tool.d.ts.map +0 -1
  213. package/dist/agents/chatbot/tools/traverse.tool.js.map +0 -1
  214. package/dist/foundations/chunk/entities/chunk.map.d.ts +0 -8
  215. package/dist/foundations/chunk/entities/chunk.map.d.ts.map +0 -1
  216. package/dist/foundations/chunk/entities/chunk.map.js +0 -31
  217. package/dist/foundations/chunk/entities/chunk.map.js.map +0 -1
  218. package/dist/foundations/chunk/entities/chunk.model.d.ts +0 -4
  219. package/dist/foundations/chunk/entities/chunk.model.d.ts.map +0 -1
  220. package/dist/foundations/chunk/entities/chunk.model.js +0 -13
  221. package/dist/foundations/chunk/entities/chunk.model.js.map +0 -1
  222. package/dist/foundations/chunk/serialisers/chunk.serialiser.d.ts +0 -14
  223. package/dist/foundations/chunk/serialisers/chunk.serialiser.d.ts.map +0 -1
  224. package/dist/foundations/chunk/serialisers/chunk.serialiser.js +0 -54
  225. package/dist/foundations/chunk/serialisers/chunk.serialiser.js.map +0 -1
  226. /package/dist/agents/{chatbot → graph}/interfaces/graph.catalog.interface.js +0 -0
  227. /package/dist/agents/{chatbot → graph}/repositories/user-modules.repository.d.ts +0 -0
  228. /package/dist/agents/{chatbot → graph}/repositories/user-modules.repository.js +0 -0
  229. /package/dist/agents/{chatbot → graph}/services/field-formatting.d.ts +0 -0
  230. /package/dist/agents/{chatbot → graph}/services/field-formatting.js +0 -0
  231. /package/dist/agents/{chatbot → graph}/services/humanize-tool.d.ts +0 -0
  232. /package/dist/agents/{chatbot → graph}/services/humanize-tool.js +0 -0
  233. /package/dist/agents/{chatbot → graph}/tools/describe-entity.tool.d.ts +0 -0
@@ -16,253 +16,97 @@ const config_1 = require("@nestjs/config");
16
16
  const zod_1 = require("zod");
17
17
  const llm_service_1 = require("../../../core/llm/services/llm.service");
18
18
  exports.defaultAnswerPrompt = `
19
- As an intelligent assistant, your primary objective is to answer questions based on information within a text.
20
- You have explored multiple paths from various starting nodes on a graph, recording key information for each path in a **notebook**.
21
- Your task now is to **analyze these memories and reason to answer the question**.
22
-
23
- ---
24
-
25
- ### **Strategy:**
26
-
27
- 1. **Provide a Title**:
28
- - Create a short **title** that the user can read as a quick reference.
29
-
30
- 2. **Analyze Notebook Content**:
31
- - Carefully review each entry in your notebook before providing a final answer.
32
- - Consider complementary information from different notes.
33
-
34
- 3. **Assess Availability of Information**:
35
- - Determine whether the notebook contains **explicit and sufficient information** to answer the question.
36
- - **Do not infer or assume information** not explicitly present in the notebook.
37
- - **If the notebook contains sufficient information**, proceed to formulate the final answer using only the information provided.
38
- - **If the notebook does NOT contain enough information**, clearly state that the answer to the question is not available in the company knowledge.
39
- - **Do not use any external information, prior knowledge, or make assumptions beyond what is in the notebook.**
40
-
41
- 4. **Citations with Relevance Scores**:
42
- - For each line in your notebook, consider the **chunkId** at the beginning of the line.
43
- - **ChunkIds are valid UUIDs** (e.g., '123e4567-e89b-12d3-a456-426614174000').
44
- - **Use only the chunkIds provided in the notebook**. **Do not invent or make up chunkIds**.
45
- - **Do not use line numbers or indices as chunkIds**.
46
- - Assign a **percentage relevance score** to indicate how much each line influenced your final answer.
47
- - This relevance score reflects the parts of your thought process used to generate the answer and will be used for citations.
48
- - **If the notebook is empty or lacks relevant information, the citations section should be empty.**
49
-
50
- 5. **Generate Follow-up Questions**:
51
- - **If sufficient information is available**, provide a list of **5 follow-up or refinement questions** based on the final answer.
52
- - **If the answer is not available**, **do not generate any follow-up questions**.
53
-
54
- 6. **Provide a Comprehensive Final Answer**:
55
- - **When sufficient information is available**, create a thorough, detailed, and well-structured response that goes beyond minimal explanations.
56
- - **Expand on concepts thoroughly**: Don't just state facts - explain them, provide context, and help users understand the complete picture.
57
- - **Use structured formatting**: Organize content with headers, subheadings, bullet points, and numbered lists to make complex information digestible.
58
- - **Be educational and informative**: Treat each answer as an opportunity to teach and provide comprehensive understanding of the topic.
59
- - **If the answer is not available**, clearly inform the user that the information is not present in the company knowledge.
60
- - **Format Requirements for Comprehensive Answers**:
61
- - Use proper markdown formatting with headers (##, ###) to organize different sections
62
- - Include bullet points or numbered lists when presenting multiple items or steps
63
- - Expand on concepts with detailed explanations rather than brief summaries
64
- - Use subheadings to break down complex topics into digestible sections
65
- - Provide context and background information when relevant to help users understand the full picture
66
- - Include examples or specific details from the notebook when available
67
- - Ensure the answer flows logically from one section to another
68
- - Make the response comprehensive, detailed, and educational rather than minimalistic
69
- - **Do not include any technical terms** such as "nodes," "text chunks," or "atomic facts" in your final answer or title.
70
- - Avoid using technical jargon and ensure the response is user-friendly while being comprehensive.
71
-
72
- ---
73
-
74
- ### **Important Notes:**
75
-
76
- - **Use Only Notebook Information**:
77
- - Do not use any external sources, prior knowledge, or make up information not present in the notebook.
78
- - Do not provide definitions, explanations, or details that are not explicitly stated in the notebook.
79
-
80
- - **No Paraphrasing Beyond Notebook Content**:
81
- - Do not restate or rephrase the notebook content as the final answer unless it directly and explicitly answers the question.
82
-
83
- - **Do Not Infer or Assume**:
84
- - Avoid making inferences or assumptions based on partial information.
85
- - If the notebook does not explicitly provide the answer, acknowledge that the information is not available.
86
-
87
- - **Do Not guess the presume to know the acronyms**:
88
- - If your notebook contains the definition of an acronym, you can use it, but if the precise definition of the acronym does NOT exist in the notebook, you must not use it.
89
- - NEVER GUESS an ACRONYM. If you don't have a clear definition in the notebook, use only the acronym and don't try to explain it.
90
- - **NEVER** write your own definitions or explanations for acronyms. An acronym is a word on its own, and you don't have to explain it.
91
-
92
- - **ChunkIds Must Match Exactly**:
93
- - Use only the actual chunkIds provided in the notebook entries.
94
- - **ChunkIds are valid UUIDs**. Do not use line numbers, indices, or any other placeholders.
95
- - **Do not invent or make up chunkIds**.
96
-
97
- - **Empty or Insufficient Notebook Handling**:
98
- - If the notebook is empty or lacks sufficient information, acknowledge this in your analysis and final answer.
99
- - **Do not provide a final answer based on assumptions or external knowledge**.
100
- - **Do not generate any follow-up questions if the answer is not available**.
101
-
102
- - **Provide Clear and User-Friendly Responses**:
103
- - Communicate clearly without technical jargon.
104
- - Do not include any technical terms such as "nodes," "text chunks," or "atomic facts" in your final answer or title.
105
-
106
- ---
107
-
108
- ### **Expected Output Format:**
109
-
110
- Your output should include the following fields in the order specified:
111
-
112
- - **Title**: A short title providing the user with a quick reference to the answer.
113
-
114
- - **Analyse**:
115
- - An analysis of the notebook content, considering complementary information and resolving inconsistencies.
116
- - State whether the notebook contains sufficient information to answer the question.
117
- - If not, acknowledge that the information is not available.
118
-
119
- - **Citations**:
120
- - A list of citations for the information you used to generate the final answer.
121
- - Each citation includes:
122
- - **chunkId**: The ID of the line in your notebook.
123
- - **relevance**: The relevance of the information in that line (as a percentage).
124
- - **If the notebook is empty or lacks relevant information, the citations section should be empty**.
125
-
126
- - **Questions**:
127
- - **If sufficient information is available**, provide a list of **5 follow-up or refinement questions** based on the final answer.
128
- - **If the answer is not available**, **do not generate any follow-up questions**.
129
-
130
- - **Final Answer**:
131
- - **If sufficient information is available**, provide a comprehensive, detailed, and well-structured answer, strictly using only the information from the notebook.
132
- - The answer should be thorough and educational, expanding on concepts with proper explanations.
133
- - Use markdown formatting with appropriate headers, subheadings, lists, and sections to organize the content clearly.
134
- - **If insufficient information is available**, state that the answer is not available in the company knowledge.
135
-
136
- ---
137
-
138
- ### **Example When Information Is Available:**
139
-
140
- **User:**
141
-
142
- Question: What is project management?
143
-
144
- Notebook of different exploration paths:
145
-
146
- - 123e4567-e89b-12d3-a456-426614174000: Project management is the application of processes, methods, skills, knowledge and experience to achieve specific project objectives.
147
- - 987f6543-e21a-34c5-b678-539725841901: Project management involves planning, organizing, securing, managing, leading, and controlling resources to achieve specific goals.
148
- - 456a1234-f56b-78c9-d012-345678901234: The primary challenge of project management is to achieve all project goals within the given constraints like time, budget, and scope.
149
-
150
- **Assistant:**
151
-
152
- **Title:**
153
-
154
- Understanding Project Management: Processes, Goals, and Constraints
155
-
156
- **Analyse:**
157
-
158
- The notebook contains comprehensive information about project management, covering its definition, key activities, and primary challenges. The information is consistent across different sources and provides a complete foundation for explaining what project management entails.
159
-
160
- **Citations:**
161
-
162
- - chunkId: "123e4567-e89b-12d3-a456-426614174000", relevance: 95
163
- - chunkId: "987f6543-e21a-34c5-b678-539725841901", relevance: 90
164
- - chunkId: "456a1234-f56b-78c9-d012-345678901234", relevance: 85
165
-
166
- **Questions:**
167
-
168
- 1. What specific methodologies are commonly used in project management?
169
- 2. How do project managers handle scope creep and changing requirements?
170
- 3. What tools and software are most effective for project planning and tracking?
171
- 4. How does project management differ across various industries?
172
- 5. What skills are essential for becoming an effective project manager?
173
-
174
- **Final Answer:**
175
-
176
- ## What is Project Management?
177
-
178
- Project management is a comprehensive discipline that involves **the application of processes, methods, skills, knowledge, and experience to achieve specific project objectives**. It represents a structured approach to turning ideas and goals into tangible results within defined parameters.
179
-
180
- ### Core Components of Project Management
181
-
182
- Project management encompasses several critical activities that work together to ensure project success:
183
-
184
- - **Planning**: Establishing clear objectives, timelines, and resource requirements
185
- - **Organizing**: Structuring teams, workflows, and project elements efficiently
186
- - **Securing**: Obtaining necessary resources, approvals, and stakeholder buy-in
187
- - **Managing**: Overseeing day-to-day operations and progress monitoring
188
- - **Leading**: Guiding teams and stakeholders toward common goals
189
- - **Controlling**: Monitoring performance and making necessary adjustments
190
-
191
- ### The Primary Challenge
192
-
193
- The fundamental challenge of project management lies in **achieving all project goals within the given constraints**. These constraints typically include:
194
-
195
- - **Time**: Meeting established deadlines and milestones
196
- - **Budget**: Staying within allocated financial resources
197
- - **Scope**: Delivering all required features and functionality without exceeding boundaries
198
-
199
- ### Why Project Management Matters
200
-
201
- Project management serves as the bridge between conceptual ideas and practical implementation. By applying systematic approaches and proven methodologies, project managers help organizations transform vision into reality while minimizing risks and maximizing efficiency.
202
-
203
- The discipline ensures that resources are used effectively, stakeholders remain aligned, and deliverables meet quality standards within the established timeframe and budget constraints.
204
-
205
- ---
206
-
207
- ### **Example When Information Is Not Available:**
208
-
209
- **User:**
210
-
211
- Question: What is Ontology?
212
-
213
- Notebook of different exploration paths:
214
-
215
- - *(Notebook is empty or does not contain relevant information.)*
216
-
217
- **Assistant:**
218
-
219
- **Title:**
220
-
221
- Information on Ontology
222
-
223
- **Analyse:**
224
-
225
- - After reviewing the notebook, there is no information available regarding the definition or explanation of ontology.
226
- - The notebook does not contain sufficient information to answer the question.
227
-
228
- **Citations:**
229
-
230
- *(No citations since the notebook is empty or lacks relevant information.)*
231
-
232
- **Questions:**
233
-
234
- *(No questions since the answer is not available.)*
235
-
236
- **Final Answer:**
237
-
238
- The answer to your question is not available in the company knowledge. There is insufficient information to explain what ontology is based on the provided data.
239
-
240
- ---
241
-
242
- ### **Please Proceed by Following These Instructions Carefully:**
243
-
244
- - **Use Only Information Provided in the Notebook**:
245
- - Do not incorporate any external knowledge or make assumptions.
246
- - Do not provide definitions or explanations that are not explicitly in the notebook.
247
-
248
- - **Do Not Restate Notebook Content as Answer**:
249
- - Unless the notebook explicitly answers the question, do not restate the notebook content as the final answer.
250
-
251
- - **ChunkIds are Valid UUIDs**:
252
- - Use only the chunkIds provided in the notebook, which are valid UUIDs (e.g., '123e4567-e89b-12d3-a456-426614174000').
253
- - **Do not invent or make up chunkIds**.
254
- - **Do not use line numbers or indices as chunkIds**.
255
-
256
- - **Handle Empty or Insufficient Notebooks Appropriately**:
257
- - If the notebook is empty or lacks sufficient information, acknowledge this in your analysis and final answer.
258
- - **Do not generate any follow-up questions if the answer is not available**.
259
-
260
- - **Provide Clear and User-Friendly Responses**:
261
- - Communicate clearly without technical jargon.
262
-
263
- ---
264
-
265
- By emphasizing that ChunkIds are valid UUIDs and that you should not invent or make up any chunkIds, as well as specifying that no follow-up questions should be generated if the answer is not available, this updated prompt should help prevent the LLM from including information from outside the notebook or making up chunkIds. It also clarifies how to handle situations where the notebook does not contain sufficient information to answer the question.
19
+ You are the synthesizer of a unified ERP assistant. You are given a user
20
+ question and the results of up to three retrieval branches that ran in
21
+ parallel before you. Your job is to write a clear, useful answer using
22
+ ONLY the data those branches returned.
23
+
24
+ ## What you receive
25
+
26
+ Each turn arrives with these inputs:
27
+
28
+ - \`question\` the user's refined question.
29
+ - \`graphSection\` — the graph branch's own prose reply about the records it
30
+ loaded, followed by an "--- entities for citation ---" block listing each
31
+ cited entity as \`[ref:N] type reason\` plus an optional JSON block of
32
+ field values. Treat the prose at the top of \`graphSection\` as the
33
+ authoritative graph result; weave it into the unified answer rather than
34
+ restating the entity list line-by-line. The \`[ref:N]\` handles are opaque
35
+ reference tokens use them only inside the \`references\` array, never
36
+ inside \`finalAnswer\` or \`title\`.
37
+ - \`notebookSection\` chunks the contextualiser branch retrieved from the
38
+ document store, each prefixed with its chunkId followed by a snippet of
39
+ text.
40
+ - \`driftSection\` — community-level summaries (when the drift branch ran).
41
+ - \`scopeSection\` optional scope hint when the conversation is bound to a
42
+ single content.
43
+ - \`branchesUsed\` list of branches that produced data this turn.
44
+
45
+ A section is the empty string \`""\` when its branch did not run. When all
46
+ data sections are empty, you have no information for this turn say so
47
+ plainly without referencing "company knowledge", "notebook", or other
48
+ system internals.
49
+
50
+ ## How to write the answer
51
+
52
+ 1. **Identify the user's intent.** Are they asking for a list, a single
53
+ fact, a procedure, a status, or a comparison? Match the answer's shape
54
+ to the question.
55
+
56
+ 2. **Use the graph branch's prose as authoritative graph data.** The
57
+ prose at the top of \`graphSection\` was written by the same component
58
+ that loaded the records; it already contains the field values, names,
59
+ and statuses. Weave it into \`finalAnswer\`. You may reorganise it,
60
+ merge it with material from \`notebookSection\` or \`driftSection\`, or
61
+ tighten the wording but do not invent values that are not in the
62
+ prose, the entity field blocks, or the chunks.
63
+
64
+ 3. **Quote chunk content faithfully.** When you draw from
65
+ \`notebookSection\`, quote or paraphrase the snippet rather than
66
+ substituting your own restatement.
67
+
68
+ 4. **Cite the chunks that grounded a document answer.** When you quote or
69
+ paraphrase from \`notebookSection\`, add the chunkId to \`citations\` with
70
+ a relevance score 0–100. Use only chunkIds that actually appear in
71
+ \`notebookSection\`. If \`notebookSection\` is empty, \`citations\` MUST be
72
+ \`[]\`.
73
+
74
+ 5. **Cite the entities that grounded a graph answer.** Every entity whose
75
+ information the answer relies on goes into \`references\` as
76
+ \`{ ref, relevance, reason }\`, with the \`ref\` handle copied verbatim
77
+ from the "entities for citation" block (e.g. \`"ref:0"\`). Never invent
78
+ a handle. Never put a chunk into \`references\`; never put an entity
79
+ into \`citations\`. If \`graphSection\` is empty, \`references\` MUST be
80
+ \`[]\`.
81
+
82
+ 6. **No handles, no UUIDs in user-facing text.** \`title\` and
83
+ \`finalAnswer\` must not contain the word "ref", the bracketed handle,
84
+ or any UUID. The handles are translated back to real (type, id) pairs
85
+ after you return.
86
+
87
+ 7. **Suggested questions are optional.** If the answer is solid and
88
+ obvious next-step questions exist, propose 3–5; otherwise return \`[]\`.
89
+ Do not return suggestions when you had no data.
90
+
91
+ 8. **No-data case.** If every data section is empty (or together they do
92
+ not cover what the user asked), say so directly. Do not say "answer
93
+ is not available in the company knowledge" that is a bad system
94
+ phrase. Return \`citations: []\` and \`references: []\` in this case.
95
+
96
+ ## Output schema
97
+
98
+ Return strictly:
99
+
100
+ - \`title\` short headline for the UI (under ~70 chars). No handles, no UUIDs.
101
+ - \`analyse\` — one to three sentences describing how you derived the answer
102
+ (which branches you used, which records you compared). Internal-facing.
103
+ No handles.
104
+ - \`finalAnswer\` the user-facing markdown answer. Use headings sparingly,
105
+ bullet lists where they help, and field values from the graph branch's
106
+ prose and entity field blocks. No handles, no UUIDs.
107
+ - \`citations\` — array of \`{ chunkId, relevance }\` for chunks you used.
108
+ - \`references\` array of \`{ ref, relevance, reason }\` for entities you used.
109
+ - \`questions\` — array of follow-up question strings.
266
110
  `;
267
111
  const outputSchema = zod_1.z.object({
268
112
  title: zod_1.z.string().describe(`You should generate a short title to provide the user a quick reference`),
@@ -277,6 +121,15 @@ const outputSchema = zod_1.z.object({
277
121
  .describe(`The relevance of the information in the line of your notebook in percentage between 0 and 100. This defines if the information is relevant to the question or not and if it will be used as a citation.`),
278
122
  }))
279
123
  .describe(`You should provide citations to the information you used to generate the final answer. Consider ALL the ChunkIds in your notebook. Each citation should have a relevance score. Each ChunkId should be unique. Each ChunkId should have a relevance score.`),
124
+ references: zod_1.z
125
+ .array(zod_1.z.object({
126
+ ref: zod_1.z
127
+ .string()
128
+ .describe('A `[ref:N]` handle copied verbatim from the "entities for citation" block of `graphSection`'),
129
+ relevance: zod_1.z.number().describe("Relevance of this entity to the final answer (0-100)"),
130
+ reason: zod_1.z.string().describe("A short justification for why the entity grounds the answer"),
131
+ }))
132
+ .describe(`The graph entities the answer is grounded on. Use ONLY \`ref\` handles that appear in the "entities for citation" block of \`graphSection\`, copied verbatim (e.g. "ref:0"). Never invent ref handles. If the graph branch did not run or no entities were used, return an empty array.`),
280
133
  questions: zod_1.z
281
134
  .array(zod_1.z.string())
282
135
  .describe(`A list of **5 follow-up or refinement questions** based on the final answer.`),
@@ -294,16 +147,14 @@ Format Requirements:
294
147
  `),
295
148
  });
296
149
  const inputSchema = zod_1.z.object({
297
- question: zod_1.z.string().describe("The question asked by the user"),
298
- annotations: zod_1.z.string().describe("A set of annotations to provide additional context"),
299
- notebook: zod_1.z
300
- .array(zod_1.z.object({
301
- chunkId: zod_1.z.string().describe("The UUID of the chunk"),
302
- content: zod_1.z
303
- .string()
304
- .describe("The note you took about the content of the text chunk in relation to the user question."),
305
- }))
306
- .describe("A set of notes identified for each chunk of text that could be used as sources"),
150
+ question: zod_1.z.string().describe("The user's refined question"),
151
+ notebookSection: zod_1.z
152
+ .string()
153
+ .describe("Notebook from the contextualiser branch (chunkId-prefixed lines), or empty if that branch did not run"),
154
+ graphSection: zod_1.z.string().describe("Graph entities discovered for the question, or empty if that branch did not run"),
155
+ driftSection: zod_1.z.string().describe("Community-level summaries from drift, or empty if that branch did not run"),
156
+ scopeSection: zod_1.z.string().describe("Optional content-scope hint, or empty"),
157
+ branchesUsed: zod_1.z.array(zod_1.z.string()).describe("Names of branches whose data is included"),
307
158
  });
308
159
  let ResponderAnswerNodeService = ResponderAnswerNodeService_1 = class ResponderAnswerNodeService {
309
160
  constructor(llmService, configService) {
@@ -314,203 +165,177 @@ let ResponderAnswerNodeService = ResponderAnswerNodeService_1 = class ResponderA
314
165
  this.systemPrompt = prompts?.responder ?? exports.defaultAnswerPrompt;
315
166
  }
316
167
  async execute(params) {
317
- const hasDriftContext = params.state.useDrift && params.state.driftContext;
318
- const hasContextualiserContext = params.state.context;
319
- // Hybrid mode: both DRIFT and Contextualiser available
320
- if (hasDriftContext && hasContextualiserContext) {
321
- return this.executeHybridMode(params);
322
- }
323
- // DRIFT-only mode (fallback, shouldn't happen with current flow)
324
- if (hasDriftContext) {
325
- return this.executeDriftMode(params);
326
- }
327
- // Contextualiser-only mode (default)
328
- return this.executeContextualiserMode(params);
329
- }
330
- /**
331
- * Execute answer generation using Contextualiser data (traditional mode)
332
- */
333
- async executeContextualiserMode(params) {
334
- const inputParams = {
335
- question: params.state.context.question,
336
- annotations: params.state.context.annotations,
337
- notebook: params.state.context.notebook,
168
+ const state = params.state;
169
+ const branchPlan = state.branchPlan ?? {
170
+ runGraph: false,
171
+ runContextualiser: false,
172
+ runDrift: false,
173
+ reasoning: "",
338
174
  };
339
- const llmResponse = await this.llmService.call({
340
- inputSchema: inputSchema,
341
- inputParams: inputParams,
342
- outputSchema: outputSchema,
343
- systemPrompts: [this.systemPrompt],
344
- temperature: 0.1,
345
- });
346
- const sources = llmResponse.citations.map((citation) => ({
347
- chunkId: citation.chunkId ?? "",
348
- relevance: citation.relevance ?? 0,
349
- reason: "",
175
+ const branchesUsed = [];
176
+ if (branchPlan.runGraph)
177
+ branchesUsed.push("graph");
178
+ if (branchPlan.runContextualiser)
179
+ branchesUsed.push("contextualiser");
180
+ if (branchPlan.runDrift)
181
+ branchesUsed.push("drift");
182
+ // Build a ref-handle map so the synthesizer never sees raw UUIDs.
183
+ const refMap = (state.graphContext?.entities ?? []).map((e, i) => ({
184
+ ref: `ref:${i}`,
185
+ type: e.type,
186
+ id: e.id,
187
+ reason: e.reason,
188
+ fields: e.fields,
350
189
  }));
351
- const filteredSources = [];
352
- for (const source of sources) {
353
- const existingSource = filteredSources.find((s) => s.chunkId === source.chunkId);
354
- const existingNote = params.state.context.notebook.find((n) => n.chunkId === source.chunkId);
355
- if (existingNote)
356
- source.reason = existingNote.reason;
357
- if (!existingSource) {
358
- filteredSources.push(source);
359
- continue;
360
- }
361
- if (source.relevance > existingSource.relevance) {
362
- existingSource.relevance = source.relevance;
363
- }
364
- }
365
- params.state.sources = filteredSources;
366
- params.state.ontologies = params.state.context.ontology;
367
- params.state.tokens = llmResponse.tokenUsage;
368
- params.state.finalAnswer = {
369
- title: llmResponse.title,
370
- answer: llmResponse.finalAnswer,
371
- analysis: llmResponse.analyse,
372
- questions: llmResponse.questions,
373
- hasAnswer: true,
374
- };
375
- return params.state;
376
- }
377
- /**
378
- * Execute answer generation using both DRIFT (global) and Contextualiser (local) data
379
- * Combines community-level insights with chunk-level citations
380
- */
381
- async executeHybridMode(params) {
382
- const driftContext = params.state.driftContext;
383
- const contextualiserContext = params.state.context;
384
- // Build enhanced context that includes DRIFT global insights
385
- const globalContext = this.buildGlobalContextSection(driftContext);
386
- // Create enhanced input with both global and local context
387
- const inputParams = {
388
- question: contextualiserContext.question,
389
- annotations: `${contextualiserContext.annotations}\n\n--- GLOBAL CONTEXT FROM KNOWLEDGE COMMUNITIES ---\n${globalContext}`,
390
- notebook: contextualiserContext.notebook,
391
- };
190
+ const notebookSection = branchPlan.runContextualiser && state.context ? this.buildNotebookSection(state.context) : "";
191
+ const graphAnswer = state.graphContext?.answer ?? "";
192
+ const graphSection = branchPlan.runGraph && state.graphContext ? this.buildGraphSection(graphAnswer, refMap) : "";
193
+ const driftSection = branchPlan.runDrift && state.driftContext ? this.buildDriftSection(state.driftContext) : "";
194
+ const scopeSection = state.contentId && state.contentType
195
+ ? `\n\n--- CONVERSATION SCOPE ---\nThe conversation is scoped to ${state.contentType}:${state.contentId}.`
196
+ : "";
197
+ this.logger.log(`answer node input: branchesUsed=${JSON.stringify(branchesUsed)} ` +
198
+ `graphEntities=${state.graphContext?.entities?.length ?? 0} ` +
199
+ `graphAnswerChars=${graphAnswer.length} ` +
200
+ `notebookChars=${notebookSection.length} ` +
201
+ `graphChars=${graphSection.length} ` +
202
+ `driftChars=${driftSection.length} ` +
203
+ `scopeChars=${scopeSection.length}`);
204
+ if (graphSection.length)
205
+ this.logger.debug(`answer node graphSection:\n${graphSection}`);
392
206
  const llmResponse = await this.llmService.call({
393
- inputSchema: inputSchema,
394
- inputParams: inputParams,
395
- outputSchema: outputSchema,
207
+ inputSchema,
208
+ inputParams: {
209
+ question: state.question ?? "",
210
+ notebookSection,
211
+ graphSection,
212
+ driftSection,
213
+ scopeSection,
214
+ branchesUsed,
215
+ },
216
+ outputSchema,
396
217
  systemPrompts: [this.systemPrompt],
397
218
  temperature: 0.1,
219
+ metadata: {
220
+ nodeName: "answer",
221
+ agentName: "responder",
222
+ userQuestion: state.question,
223
+ },
398
224
  });
399
- // Process citations from contextualiser notebook
400
- const sources = llmResponse.citations.map((citation) => ({
401
- chunkId: citation.chunkId ?? "",
402
- relevance: citation.relevance ?? 0,
225
+ // Sources chunks from the contextualiser branch
226
+ const sources = (llmResponse.citations ?? []).map((c) => ({
227
+ chunkId: c.chunkId ?? "",
228
+ relevance: c.relevance ?? 0,
403
229
  reason: "",
404
230
  }));
405
- const filteredSources = [];
406
- for (const source of sources) {
407
- const existingSource = filteredSources.find((s) => s.chunkId === source.chunkId);
408
- const existingNote = contextualiserContext.notebook.find((n) => n.chunkId === source.chunkId);
409
- if (existingNote)
410
- source.reason = existingNote.reason;
411
- if (!existingSource) {
412
- filteredSources.push(source);
413
- continue;
414
- }
415
- if (source.relevance > existingSource.relevance) {
416
- existingSource.relevance = source.relevance;
231
+ if (state.context) {
232
+ for (const s of sources) {
233
+ const note = state.context.notebook?.find((n) => n.chunkId === s.chunkId);
234
+ if (note)
235
+ s.reason = note.reason;
417
236
  }
418
237
  }
419
- params.state.sources = filteredSources;
420
- params.state.ontologies = contextualiserContext.ontology;
421
- // Combine token usage from both DRIFT and this call
422
- params.state.tokens = {
423
- input: (params.state.tokens?.input || 0) + (llmResponse.tokenUsage?.input || 0),
424
- output: (params.state.tokens?.output || 0) + (llmResponse.tokenUsage?.output || 0),
238
+ const filteredSources = this.deduplicateByChunkId(sources);
239
+ // References — remap [ref:N] handles back to (type, id). Drop any handle the
240
+ // synthesizer invented that doesn't appear in the graph node's output.
241
+ const byRef = new Map(refMap.map((e) => [e.ref, e]));
242
+ const references = (llmResponse.references ?? [])
243
+ .map((r) => {
244
+ const hit = byRef.get(r.ref);
245
+ if (!hit)
246
+ return null;
247
+ return {
248
+ type: hit.type,
249
+ id: hit.id,
250
+ relevance: Math.max(0, Math.min(100, r.relevance ?? 0)),
251
+ reason: r.reason ?? "",
252
+ };
253
+ })
254
+ .filter((x) => x !== null);
255
+ const llmRefCount = (llmResponse.references ?? []).length;
256
+ const droppedRefs = llmRefCount - references.length;
257
+ this.logger.log(`answer node done: title=${JSON.stringify(llmResponse.title)} ` +
258
+ `finalAnswerChars=${(llmResponse.finalAnswer ?? "").length} ` +
259
+ `citations=${filteredSources.length} ` +
260
+ `references=${references.length}${droppedRefs > 0 ? ` (${droppedRefs} hallucinated dropped)` : ""} ` +
261
+ `tokens=${JSON.stringify(llmResponse.tokenUsage ?? { input: 0, output: 0 })}`);
262
+ if (llmRefCount === 0 && (state.graphContext?.entities?.length ?? 0) > 0) {
263
+ this.logger.warn(`answer node returned 0 references despite ${state.graphContext?.entities?.length} graph entities being available — synthesizer prompt likely needs reinforcement`);
264
+ }
265
+ state.sources = filteredSources;
266
+ state.references = references;
267
+ state.ontologies = state.context?.ontology ?? [];
268
+ state.tokens = {
269
+ input: (state.tokens?.input || 0) + (llmResponse.tokenUsage?.input || 0),
270
+ output: (state.tokens?.output || 0) + (llmResponse.tokenUsage?.output || 0),
425
271
  };
426
- params.state.finalAnswer = {
272
+ state.finalAnswer = {
427
273
  title: llmResponse.title,
428
- answer: llmResponse.finalAnswer,
429
274
  analysis: llmResponse.analyse,
430
- questions: llmResponse.questions,
431
- hasAnswer: true,
275
+ answer: llmResponse.finalAnswer,
276
+ questions: llmResponse.questions ?? [],
277
+ hasAnswer: branchesUsed.length > 0 || filteredSources.length + references.length > 0,
278
+ };
279
+ state.trace = {
280
+ ...state.trace,
281
+ answer: { branchesUsed, tokens: llmResponse.tokenUsage ?? { input: 0, output: 0 } },
282
+ totalTokens: state.tokens,
432
283
  };
433
- return params.state;
284
+ return state;
434
285
  }
435
- /**
436
- * Build global context section from DRIFT search results
437
- */
438
- buildGlobalContextSection(driftContext) {
439
- const sections = [];
440
- // Add matched communities summary
441
- if (driftContext.matchedCommunities?.length > 0) {
442
- sections.push("## Relevant Knowledge Communities\n");
443
- for (const community of driftContext.matchedCommunities) {
444
- sections.push(`### ${community.name || "Community"}`);
445
- if (community.summary) {
446
- sections.push(community.summary);
447
- }
448
- sections.push("");
449
- }
450
- }
451
- // Add DRIFT's initial answer as additional context
452
- if (driftContext.initialAnswer) {
453
- sections.push("## Initial Analysis\n");
454
- sections.push(driftContext.initialAnswer);
455
- sections.push("");
286
+ buildNotebookSection(ctx) {
287
+ const lines = ["", "--- NOTEBOOK (chunks discovered) ---"];
288
+ if (ctx.annotations)
289
+ lines.push(ctx.annotations);
290
+ for (const n of ctx.notebook ?? [])
291
+ lines.push(`${n.chunkId}: ${n.content}`);
292
+ return lines.join("\n");
293
+ }
294
+ buildGraphSection(graphAnswer, refMap) {
295
+ const lines = ["", "--- GRAPH BRANCH ---"];
296
+ if (graphAnswer.trim().length > 0) {
297
+ lines.push("", graphAnswer.trim());
456
298
  }
457
- // Add follow-up investigation findings
458
- if (driftContext.followUpAnswers?.length > 0) {
459
- sections.push("## Additional Findings\n");
460
- for (const followUp of driftContext.followUpAnswers) {
461
- sections.push(`**${followUp.question}**`);
462
- sections.push(followUp.answer);
463
- sections.push("");
299
+ lines.push("", "--- entities for citation ---");
300
+ for (const e of refMap) {
301
+ lines.push(`[${e.ref}] ${e.type} — ${e.reason}`);
302
+ if (e.fields && Object.keys(e.fields).length > 0) {
303
+ lines.push(JSON.stringify(e.fields, null, 2));
464
304
  }
465
305
  }
466
- // Add confidence indicator
467
- if (driftContext.confidence !== undefined) {
468
- const confidenceLevel = driftContext.confidence >= 70 ? "high" : driftContext.confidence >= 40 ? "medium" : "low";
469
- sections.push(`_Global search confidence: ${confidenceLevel} (${driftContext.confidence}%)_`);
470
- }
471
- return sections.join("\n");
472
- }
473
- /**
474
- * Execute answer generation using DRIFT search data
475
- * DRIFT already provides a synthesized answer, so we format it for the response
476
- */
477
- async executeDriftMode(params) {
478
- const driftContext = params.state.driftContext;
479
- // Extract questions from follow-up answers
480
- const questions = driftContext.followUpAnswers?.slice(0, 5).map((f) => f.question) ?? [];
481
- // Generate title from matched communities
482
- const communityNames = driftContext.matchedCommunities?.map((c) => c.name).filter(Boolean) ?? [];
483
- const title = communityNames.length > 0 ? `Answer based on: ${communityNames.slice(0, 3).join(", ")}` : "DRIFT Search Result";
484
- // Build analysis from DRIFT information
485
- const analysis = this.buildDriftAnalysis(driftContext);
486
- // Sources from matched communities (no chunk-level sources in DRIFT)
487
- params.state.sources = [];
488
- params.state.ontologies = [];
489
- params.state.finalAnswer = {
490
- title,
491
- answer: driftContext.answer,
492
- analysis,
493
- questions,
494
- hasAnswer: driftContext.confidence > 10,
495
- };
496
- return params.state;
306
+ return lines.join("\n");
497
307
  }
498
- /**
499
- * Build analysis text from DRIFT context
500
- */
501
- buildDriftAnalysis(driftContext) {
502
- const parts = [];
503
- if (driftContext.matchedCommunities?.length > 0) {
504
- parts.push(`Searched ${driftContext.matchedCommunities.length} knowledge communities.`);
308
+ buildDriftSection(d) {
309
+ const parts = ["", "--- DRIFT (community-level summaries) ---"];
310
+ if (d.matchedCommunities?.length) {
311
+ for (const c of d.matchedCommunities) {
312
+ parts.push(`### ${c.name ?? "Community"}`);
313
+ if (c.summary)
314
+ parts.push(c.summary);
315
+ }
505
316
  }
506
- if (driftContext.confidence !== undefined) {
507
- const confidenceLevel = driftContext.confidence >= 70 ? "high" : driftContext.confidence >= 40 ? "medium" : "low";
508
- parts.push(`Confidence level: ${confidenceLevel} (${driftContext.confidence}%).`);
317
+ if (d.initialAnswer)
318
+ parts.push(`Initial analysis: ${d.initialAnswer}`);
319
+ if (d.followUpAnswers?.length) {
320
+ for (const f of d.followUpAnswers)
321
+ parts.push(`${f.question} → ${f.answer}`);
509
322
  }
510
- if (driftContext.followUpAnswers?.length > 0) {
511
- parts.push(`Conducted ${driftContext.followUpAnswers.length} follow-up investigations for depth.`);
323
+ if (d.confidence !== undefined)
324
+ parts.push(`Drift confidence: ${d.confidence}%`);
325
+ return parts.join("\n");
326
+ }
327
+ deduplicateByChunkId(sources) {
328
+ const out = [];
329
+ for (const s of sources) {
330
+ const existing = out.find((o) => o.chunkId === s.chunkId);
331
+ if (!existing) {
332
+ out.push(s);
333
+ continue;
334
+ }
335
+ if (s.relevance > existing.relevance)
336
+ existing.relevance = s.relevance;
512
337
  }
513
- return parts.join(" ");
338
+ return out;
514
339
  }
515
340
  };
516
341
  exports.ResponderAnswerNodeService = ResponderAnswerNodeService;