@carlonicora/nestjs-neo4jsonapi 2.14.10 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/contextualiser/contexts/contextualiser.context.d.ts +41 -0
- package/dist/agents/contextualiser/contexts/contextualiser.context.d.ts.map +1 -1
- package/dist/agents/contextualiser/contexts/contextualiser.context.js +17 -0
- package/dist/agents/contextualiser/contexts/contextualiser.context.js.map +1 -1
- package/dist/agents/contextualiser/contexts/notebook.context.d.ts +22 -0
- package/dist/agents/contextualiser/contexts/notebook.context.d.ts.map +1 -1
- package/dist/agents/contextualiser/contexts/notebook.context.js +14 -0
- package/dist/agents/contextualiser/contexts/notebook.context.js.map +1 -1
- package/dist/agents/contextualiser/factories/contextualiser.context.factory.d.ts.map +1 -1
- package/dist/agents/contextualiser/factories/contextualiser.context.factory.js +2 -0
- package/dist/agents/contextualiser/factories/contextualiser.context.factory.js.map +1 -1
- package/dist/agents/contextualiser/nodes/atomicfacts.node.service.d.ts.map +1 -1
- package/dist/agents/contextualiser/nodes/atomicfacts.node.service.js +17 -5
- package/dist/agents/contextualiser/nodes/atomicfacts.node.service.js.map +1 -1
- package/dist/agents/contextualiser/nodes/chunk.node.service.d.ts +1 -14
- package/dist/agents/contextualiser/nodes/chunk.node.service.d.ts.map +1 -1
- package/dist/agents/contextualiser/nodes/chunk.node.service.js +56 -206
- package/dist/agents/contextualiser/nodes/chunk.node.service.js.map +1 -1
- package/dist/agents/contextualiser/nodes/chunk.vector.node.service.d.ts +3 -12
- package/dist/agents/contextualiser/nodes/chunk.vector.node.service.d.ts.map +1 -1
- package/dist/agents/contextualiser/nodes/chunk.vector.node.service.js +44 -133
- package/dist/agents/contextualiser/nodes/chunk.vector.node.service.js.map +1 -1
- package/dist/agents/contextualiser/nodes/keyconcepts.node.service.d.ts +1 -2
- package/dist/agents/contextualiser/nodes/keyconcepts.node.service.d.ts.map +1 -1
- package/dist/agents/contextualiser/nodes/keyconcepts.node.service.js +60 -60
- package/dist/agents/contextualiser/nodes/keyconcepts.node.service.js.map +1 -1
- package/dist/agents/contextualiser/nodes/question.refiner.node.service.d.ts.map +1 -1
- package/dist/agents/contextualiser/nodes/question.refiner.node.service.js +7 -2
- package/dist/agents/contextualiser/nodes/question.refiner.node.service.js.map +1 -1
- package/dist/agents/contextualiser/nodes/rational.node.service.js +2 -1
- package/dist/agents/contextualiser/nodes/rational.node.service.js.map +1 -1
- package/dist/agents/contextualiser/services/contextualiser.service.d.ts.map +1 -1
- package/dist/agents/contextualiser/services/contextualiser.service.js +30 -22
- package/dist/agents/contextualiser/services/contextualiser.service.js.map +1 -1
- package/dist/agents/prompts/index.d.ts +0 -2
- package/dist/agents/prompts/index.d.ts.map +1 -1
- package/dist/agents/prompts/index.js +7 -5
- package/dist/agents/prompts/index.js.map +1 -1
- package/dist/agents/responder/contexts/responder.context.d.ts +96 -0
- package/dist/agents/responder/contexts/responder.context.d.ts.map +1 -1
- package/dist/agents/responder/interfaces/unified.trace.interface.d.ts +9 -0
- package/dist/agents/responder/interfaces/unified.trace.interface.d.ts.map +1 -1
- package/dist/agents/responder/nodes/__tests__/helpers/answer-node.harness.d.ts +38 -0
- package/dist/agents/responder/nodes/__tests__/helpers/answer-node.harness.d.ts.map +1 -0
- package/dist/agents/responder/nodes/__tests__/helpers/answer-node.harness.js +36 -0
- package/dist/agents/responder/nodes/__tests__/helpers/answer-node.harness.js.map +1 -0
- package/dist/agents/responder/nodes/graph.node.service.d.ts.map +1 -1
- package/dist/agents/responder/nodes/graph.node.service.js +18 -3
- package/dist/agents/responder/nodes/graph.node.service.js.map +1 -1
- package/dist/agents/responder/nodes/planner.node.service.d.ts.map +1 -1
- package/dist/agents/responder/nodes/planner.node.service.js +9 -0
- package/dist/agents/responder/nodes/planner.node.service.js.map +1 -1
- package/dist/agents/responder/nodes/responder.answer.node.service.d.ts +26 -1
- package/dist/agents/responder/nodes/responder.answer.node.service.d.ts.map +1 -1
- package/dist/agents/responder/nodes/responder.answer.node.service.js +127 -13
- package/dist/agents/responder/nodes/responder.answer.node.service.js.map +1 -1
- package/dist/agents/responder/services/responder.service.d.ts.map +1 -1
- package/dist/agents/responder/services/responder.service.js +4 -0
- package/dist/agents/responder/services/responder.service.js.map +1 -1
- package/dist/common/utils/settled.d.ts +33 -0
- package/dist/common/utils/settled.d.ts.map +1 -0
- package/dist/common/utils/settled.js +66 -0
- package/dist/common/utils/settled.js.map +1 -0
- package/dist/config/interfaces/config.prompts.interface.d.ts +12 -0
- package/dist/config/interfaces/config.prompts.interface.d.ts.map +1 -1
- package/dist/core/llm/services/model.service.d.ts.map +1 -1
- package/dist/core/llm/services/model.service.js +5 -2
- package/dist/core/llm/services/model.service.js.map +1 -1
- package/dist/core/llm/services/reasoning-content-fetch.d.ts +41 -0
- package/dist/core/llm/services/reasoning-content-fetch.d.ts.map +1 -0
- package/dist/core/llm/services/reasoning-content-fetch.js +143 -0
- package/dist/core/llm/services/reasoning-content-fetch.js.map +1 -0
- package/dist/eval/retrieval/end-to-end-sweep.service.d.ts +52 -0
- package/dist/eval/retrieval/end-to-end-sweep.service.d.ts.map +1 -0
- package/dist/eval/retrieval/end-to-end-sweep.service.js +194 -0
- package/dist/eval/retrieval/end-to-end-sweep.service.js.map +1 -0
- package/dist/eval/retrieval/evidence.matcher.d.ts +23 -0
- package/dist/eval/retrieval/evidence.matcher.d.ts.map +1 -0
- package/dist/eval/retrieval/evidence.matcher.js +38 -0
- package/dist/eval/retrieval/evidence.matcher.js.map +1 -0
- package/dist/eval/retrieval/index.d.ts +10 -0
- package/dist/eval/retrieval/index.d.ts.map +1 -0
- package/dist/eval/retrieval/index.js +35 -0
- package/dist/eval/retrieval/index.js.map +1 -0
- package/dist/eval/retrieval/question-set.loader.d.ts +16 -0
- package/dist/eval/retrieval/question-set.loader.d.ts.map +1 -0
- package/dist/eval/retrieval/question-set.loader.js +73 -0
- package/dist/eval/retrieval/question-set.loader.js.map +1 -0
- package/dist/eval/retrieval/retrieval-eval.module.d.ts +14 -0
- package/dist/eval/retrieval/retrieval-eval.module.d.ts.map +1 -0
- package/dist/eval/retrieval/retrieval-eval.module.js +48 -0
- package/dist/eval/retrieval/retrieval-eval.module.js.map +1 -0
- package/dist/eval/retrieval/retrieval-eval.types.d.ts +84 -0
- package/dist/eval/retrieval/retrieval-eval.types.d.ts.map +1 -0
- package/dist/eval/retrieval/retrieval-eval.types.js +25 -0
- package/dist/eval/retrieval/retrieval-eval.types.js.map +1 -0
- package/dist/eval/retrieval/retrieval-sweep.service.d.ts +35 -0
- package/dist/eval/retrieval/retrieval-sweep.service.d.ts.map +1 -0
- package/dist/eval/retrieval/retrieval-sweep.service.js +93 -0
- package/dist/eval/retrieval/retrieval-sweep.service.js.map +1 -0
- package/dist/eval/retrieval/rubric-judge.service.d.ts +30 -0
- package/dist/eval/retrieval/rubric-judge.service.d.ts.map +1 -0
- package/dist/eval/retrieval/rubric-judge.service.js +138 -0
- package/dist/eval/retrieval/rubric-judge.service.js.map +1 -0
- package/dist/eval/retrieval/sweep-report.d.ts +11 -0
- package/dist/eval/retrieval/sweep-report.d.ts.map +1 -0
- package/dist/eval/retrieval/sweep-report.js +79 -0
- package/dist/eval/retrieval/sweep-report.js.map +1 -0
- package/dist/eval/retrieval/token-accounting.check.d.ts +39 -0
- package/dist/eval/retrieval/token-accounting.check.d.ts.map +1 -0
- package/dist/eval/retrieval/token-accounting.check.js +75 -0
- package/dist/eval/retrieval/token-accounting.check.js.map +1 -0
- package/dist/foundations/atomicfact/repositories/atomicfact.repository.d.ts.map +1 -1
- package/dist/foundations/atomicfact/repositories/atomicfact.repository.js +7 -0
- package/dist/foundations/atomicfact/repositories/atomicfact.repository.js.map +1 -1
- package/dist/foundations/chunk/repositories/chunk.repository.d.ts +87 -1
- package/dist/foundations/chunk/repositories/chunk.repository.d.ts.map +1 -1
- package/dist/foundations/chunk/repositories/chunk.repository.js +239 -50
- package/dist/foundations/chunk/repositories/chunk.repository.js.map +1 -1
- package/dist/foundations/chunk/repositories/retrieval.constants.d.ts +69 -0
- package/dist/foundations/chunk/repositories/retrieval.constants.d.ts.map +1 -0
- package/dist/foundations/chunk/repositories/retrieval.constants.js +72 -0
- package/dist/foundations/chunk/repositories/retrieval.constants.js.map +1 -0
- package/dist/foundations/keyconcept/repositories/keyconcept.repository.d.ts +2 -0
- package/dist/foundations/keyconcept/repositories/keyconcept.repository.d.ts.map +1 -1
- package/dist/foundations/keyconcept/repositories/keyconcept.repository.js +9 -5
- package/dist/foundations/keyconcept/repositories/keyconcept.repository.js.map +1 -1
- package/package.json +1 -1
|
@@ -8,245 +8,95 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
-
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
-
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
-
};
|
|
14
11
|
var ChunkNodeService_1;
|
|
15
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.ChunkNodeService =
|
|
13
|
+
exports.ChunkNodeService = void 0;
|
|
17
14
|
const common_1 = require("@nestjs/common");
|
|
18
|
-
const config_1 = require("@nestjs/config");
|
|
19
|
-
const nestjs_cls_1 = require("nestjs-cls");
|
|
20
|
-
const zod_1 = require("zod");
|
|
21
|
-
const llm_service_1 = require("../../../core/llm/services/llm.service");
|
|
22
|
-
const websocket_service_1 = require("../../../core/websocket/services/websocket.service");
|
|
23
15
|
const chunk_repository_1 = require("../../../foundations/chunk/repositories/chunk.repository");
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
2. Write an note summarizing the key points from the current text chunk that are relevant to the question
|
|
34
|
-
- The note should contain all the information required to provide a detailed answer
|
|
35
|
-
- The note should be a comprehensive summary that can be used to generate a precise, contextualised response to the question, containing all the required details enough to cover all relevant aspects.
|
|
36
|
-
|
|
37
|
-
3. Write a reason describing how the text chunk is relevant to the question
|
|
38
|
-
- The reason should explain why the text chunk is relevant or not to answer the question.
|
|
39
|
-
|
|
40
|
-
4. Select the appropriate next action to take based on your assessment of the current information.
|
|
41
|
-
- **queuePreviousChunk**: Choose this action if you feel that the current chunk of text might have relevant information in a previous text chunk that would **significantly** enhance your answer. Do not select this action if you believe the current chunk is either sufficient or completely irrelevant.
|
|
42
|
-
- **queueNextChunk**: Choose this action if you feel that the current chunk of text might have relevant information in a subsequent text chunk that would **significantly** enhance your answer. Do not select this action if you believe the current chunk is either sufficient or completely irrelevant.
|
|
43
|
-
- **readNeighbouringNodes**: Choose this action if you believe that this text chunk does not contain relevant information and that exploring neighbouring chunks could provide valuable context.
|
|
44
|
-
- **answer**: Choose this action if you believe that the information in this text chunk is sufficient to provide a **comprehensive and accurate** answer to the question.
|
|
45
|
-
- **skip**: Choose this action if you believe that the current chunk of text is not relevant to the question and that you want to move on to the next chunk without taking any further action.
|
|
46
|
-
|
|
47
|
-
5. **Provide a Status Message**:
|
|
48
|
-
- Write a **short, friendly message** (maximum 40 characters) about your action.
|
|
49
|
-
- **Avoid technical terms** such as "nodes", "atomic facts", or "key concepts".
|
|
50
|
-
- The status message should make the user understand the action being taken
|
|
51
|
-
- The status message **MUST** contain clear information contextualised to the current question and the gathered information.
|
|
52
|
-
- The status message should be specific to the context and clearly convey the next steps or actions being taken.
|
|
53
|
-
- The status message **MUST NOT** be something unrelated to the text, such as "success", "sufficient information", "insufficient information", "chunk analysed", "chunk processed" or similar generic messages.
|
|
54
|
-
|
|
55
|
-
### Important Notes:
|
|
56
|
-
- **Proceed to Answer When Appropriate**: If the current information is sufficient to provide a reliable answer, do not hesitate to proceed to select **answer** as the next step.
|
|
57
|
-
- **Gather More Information When Needed**: If you identify gaps or uncertainties that could be addressed by additional information, choose the appropriate action to gather that information.
|
|
58
|
-
- **Use Judgment in Decision-Making**: Apply thoughtful consideration to decide whether additional information is necessary.
|
|
59
|
-
- If the content contains acronyms and their definition, include the definition of the acronym in your answer.
|
|
60
|
-
|
|
61
|
-
### **Please strictly follow the above instructions and format. Let's begin.**
|
|
62
|
-
`;
|
|
63
|
-
const outputSchema = zod_1.z.object({
|
|
64
|
-
status: zod_1.z
|
|
65
|
-
.string()
|
|
66
|
-
.describe(`Write a short, friendly message (max 40 characters) about your action, avoiding technical terms such as "nodes" or "atomic facts" or "key concepts". Give flavour to the message and avoid repeating the same message.`),
|
|
67
|
-
note: zod_1.z
|
|
68
|
-
.object({
|
|
69
|
-
content: zod_1.z.string().describe("The new insights and findings about the question from current text"),
|
|
70
|
-
reason: zod_1.z.string().describe("The reason describing how the text chunk is relevant to the question"),
|
|
71
|
-
})
|
|
72
|
-
.describe("The note summarizing the key points from the current text chunk that are relevant to the question"),
|
|
73
|
-
chosenAction: zod_1.z.string()
|
|
74
|
-
.describe(`This is the action you have decided to do in the next step. You **MUST** pick one of the following actions:
|
|
75
|
-
- **queuePreviousChunk**: Choose this action if you feel that the previous text chunk contains valuable information for answering the question. Do not select this action if you believe the current chunk is either sufficient or completely irrelevant.
|
|
76
|
-
- **queueNextChunk**: Choose this action if you feel that the subsequent text chunk contains valuable information for answering the question. Do not select this action if you believe the current chunk is either sufficient or completely irrelevant.
|
|
77
|
-
- **readNeighbouringNodes**: Choose this action if you feel that the current text contains valuable, but somewhat incomplete information that could be clarified by exploring related concepts.
|
|
78
|
-
- **answer**: Choose this action if you believe that the information you have currently obtained is enough to answer the question. This will allow you to summarize the gathered information and provide a final answer.
|
|
79
|
-
- **skip**: Choose this action if you believe that the current chunk of text is not relevant to the question and that you want to move on to the next chunk without taking any further action.
|
|
80
|
-
`),
|
|
81
|
-
});
|
|
82
|
-
const inputSchema = zod_1.z.object({
|
|
83
|
-
question: zod_1.z.string().describe("The question asked by the user"),
|
|
84
|
-
rationalPlan: zod_1.z
|
|
85
|
-
.string()
|
|
86
|
-
.describe("The rational plan you designed to provide a comprehensive answer to the user question"),
|
|
87
|
-
text: zod_1.z.string().describe("The content of the text you must analyse to provide an answer to the user question"),
|
|
88
|
-
});
|
|
16
|
+
/**
|
|
17
|
+
* How many chunks either side of a retrieved chunk are read with it. The same
|
|
18
|
+
* value, for the same reason, as in `chunk.vector.node.service.ts`: a chunk
|
|
19
|
+
* boundary is an artefact of the splitter, not of the document, so the sentence
|
|
20
|
+
* that completes a fact often sits one chunk away. Duplicating one integer is
|
|
21
|
+
* cheaper than a shared import across two node files; the value is documented
|
|
22
|
+
* in both.
|
|
23
|
+
*/
|
|
24
|
+
const NEIGHBOR_WINDOW = 1;
|
|
89
25
|
let ChunkNodeService = ChunkNodeService_1 = class ChunkNodeService {
|
|
90
|
-
constructor(
|
|
91
|
-
this.llmService = llmService;
|
|
26
|
+
constructor(chunkRepository) {
|
|
92
27
|
this.chunkRepository = chunkRepository;
|
|
93
|
-
this.webSocketService = webSocketService;
|
|
94
|
-
this.clsService = clsService;
|
|
95
|
-
this.configService = configService;
|
|
96
|
-
this.contributedTools = contributedTools;
|
|
97
28
|
this.logger = new common_1.Logger(ChunkNodeService_1.name);
|
|
98
|
-
const prompts = this.configService.get("prompts");
|
|
99
|
-
this.systemPrompt = prompts?.contextualiser?.chunk ?? exports.defaultChunkPrompt;
|
|
100
29
|
}
|
|
101
30
|
async execute(params) {
|
|
102
31
|
if (params.state.queuedChunks.length === 0) {
|
|
103
32
|
this.logger.warn(`chunks → ${params.state.neighbouringAlreadyExplored ? "answer" : "neighbouring_nodes"} ` +
|
|
104
33
|
`(no queued chunks): processedChunks=${params.state.processedChunks.length}`);
|
|
105
34
|
return {
|
|
35
|
+
llmCalls: 0,
|
|
106
36
|
nextStep: params.state.neighbouringAlreadyExplored ? "answer" : "neighbouring_nodes",
|
|
107
37
|
};
|
|
108
38
|
}
|
|
109
|
-
const chunks = [];
|
|
110
39
|
const chunkIdsToProcess = params.state.queuedChunks.filter((chunkId) => !params.state.processedChunks.includes(chunkId));
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
chunks.push(chunk);
|
|
120
|
-
}
|
|
121
|
-
this.logger.log(`chunk lookup → ${chunks.length}/${queuedCount} chunks found by id ` + `(missing=${queuedCount - chunks.length})`);
|
|
122
|
-
if (chunks.length === 0) {
|
|
40
|
+
const fetched = await this.chunkRepository.findChunksByIds({
|
|
41
|
+
chunkIds: chunkIdsToProcess,
|
|
42
|
+
dataLimits: params.state.limits,
|
|
43
|
+
queryEmbedding: params.state.questionEmbedding,
|
|
44
|
+
});
|
|
45
|
+
this.logger.log(`chunk lookup → ${fetched.length}/${chunkIdsToProcess.length} chunks found by id ` +
|
|
46
|
+
`(missing=${chunkIdsToProcess.length - fetched.length})`);
|
|
47
|
+
if (fetched.length === 0) {
|
|
123
48
|
this.logger.warn(`chunks → ${params.state.neighbouringAlreadyExplored ? "answer" : "neighbouring_nodes"} ` +
|
|
124
|
-
`(0 chunks resolved from ${
|
|
49
|
+
`(0 chunks resolved from ${chunkIdsToProcess.length} ids — chunkIds may belong to deleted HowTos or company-scoped MATCH failed)`);
|
|
125
50
|
return {
|
|
126
51
|
queuedChunks: [],
|
|
52
|
+
llmCalls: 0,
|
|
127
53
|
nextStep: params.state.neighbouringAlreadyExplored ? "answer" : "neighbouring_nodes",
|
|
128
54
|
};
|
|
129
55
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
await this.webSocketService.sendMessageToUser(this.clsService.get("userId"), "contextualiser", {
|
|
151
|
-
message: llmResponse.status,
|
|
152
|
-
conversationId: params.state.contentId,
|
|
153
|
-
});
|
|
56
|
+
// Every fetched chunk is kept. Filtering by score was measured to be
|
|
57
|
+
// either inert (the relative bar admits everything on this corpus) or
|
|
58
|
+
// lossy (a count cap of 8 loses required evidence), so the notebook
|
|
59
|
+
// character budget in responder.answer.node.service.ts is what decides
|
|
60
|
+
// what reaches the answer. Ordering is how the budget knows what to drop.
|
|
61
|
+
const kept = [...fetched].sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
|
|
62
|
+
// Neighbour-window widening: each chunk is carried into the notebook
|
|
63
|
+
// together with the chunks immediately before/after it, so the answer node
|
|
64
|
+
// reads continuous prose instead of a splitter's arbitrary slice. This is
|
|
65
|
+
// the automatic replacement for the per-chunk LLM decision that used to
|
|
66
|
+
// queue a previous/next chunk for another round.
|
|
67
|
+
const neighborRecords = await this.chunkRepository.findChunkNeighbors({
|
|
68
|
+
chunkIds: kept.map((chunk) => chunk.id),
|
|
69
|
+
window: NEIGHBOR_WINDOW,
|
|
70
|
+
});
|
|
71
|
+
const neighborById = new Map(neighborRecords.map((neighbour) => [neighbour.chunkId, neighbour]));
|
|
72
|
+
const newNotebookEntries = kept
|
|
73
|
+
.filter((chunk) => chunk.content && chunk.content.trim() !== "")
|
|
74
|
+
.map((chunk) => {
|
|
75
|
+
const neighbours = neighborById.get(chunk.id);
|
|
154
76
|
return {
|
|
155
77
|
chunkId: chunk.id,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
tokens: llmResponse.tokenUsage,
|
|
78
|
+
content: neighbours ? [...neighbours.before, chunk.content, ...neighbours.after].join("\n\n") : chunk.content,
|
|
79
|
+
reason: "",
|
|
80
|
+
sourceLayer: "case",
|
|
81
|
+
metadata: undefined,
|
|
82
|
+
score: chunk.score,
|
|
83
|
+
coreContent: chunk.content,
|
|
163
84
|
};
|
|
164
|
-
})
|
|
165
|
-
const tokenUsed = {
|
|
166
|
-
input: 0,
|
|
167
|
-
output: 0,
|
|
168
|
-
};
|
|
169
|
-
const newNotebookEntries = [];
|
|
170
|
-
const statuses = [];
|
|
171
|
-
for (const llmResponse of llmResponses.filter((response) => !!response)) {
|
|
172
|
-
tokenUsed.input += llmResponse.tokens.input;
|
|
173
|
-
tokenUsed.output += llmResponse.tokens.output;
|
|
174
|
-
if (llmResponse.chosenAction !== "skip")
|
|
175
|
-
newNotebookEntries.push({
|
|
176
|
-
chunkId: llmResponse.chunkId,
|
|
177
|
-
content: llmResponse.note.content,
|
|
178
|
-
reason: llmResponse.note.reason,
|
|
179
|
-
sourceLayer: "case",
|
|
180
|
-
metadata: undefined,
|
|
181
|
-
});
|
|
182
|
-
if (!statuses.includes(llmResponse.status) && !params.state.status.includes(llmResponse.status))
|
|
183
|
-
statuses.push(llmResponse.status);
|
|
184
|
-
}
|
|
185
|
-
const newChunksToQuery = [];
|
|
186
|
-
await Promise.all(llmResponses
|
|
187
|
-
.filter((response) => !!response)
|
|
188
|
-
.map(async (llmResponse) => {
|
|
189
|
-
switch (llmResponse.chosenAction) {
|
|
190
|
-
case "queueNextChunk":
|
|
191
|
-
const nextChunk = await this.chunkRepository.findSubsequentChunkId({
|
|
192
|
-
chunkId: llmResponse.chunkId,
|
|
193
|
-
});
|
|
194
|
-
if (nextChunk)
|
|
195
|
-
newChunksToQuery.push(nextChunk.id);
|
|
196
|
-
break;
|
|
197
|
-
case "queuePreviousChunk":
|
|
198
|
-
const previousChunk = await this.chunkRepository.findPreviousChunkId({
|
|
199
|
-
chunkId: llmResponse.chunkId,
|
|
200
|
-
});
|
|
201
|
-
if (previousChunk)
|
|
202
|
-
newChunksToQuery.push(previousChunk.id);
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
}));
|
|
206
|
-
let nextStep;
|
|
207
|
-
if (newChunksToQuery.length > 0) {
|
|
208
|
-
nextStep = "chunks";
|
|
209
|
-
}
|
|
210
|
-
else if (llmResponses.filter((response) => !!response).some((llmResponse) => llmResponse.chosenAction === "answer") ===
|
|
211
|
-
true) {
|
|
212
|
-
nextStep = "answer";
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
if (params.state.neighbouringAlreadyExplored)
|
|
216
|
-
nextStep = "answer";
|
|
217
|
-
else
|
|
218
|
-
nextStep = "neighbouring_nodes";
|
|
219
|
-
}
|
|
220
|
-
// Safety checks to prevent excessive looping:
|
|
221
|
-
// 1. Local check: If we've gone through chunks more than 3 times
|
|
222
|
-
// 2. Global check: If we're approaching the maxHops limit (typically 20, leave 5 hop buffer)
|
|
223
|
-
const approachingMaxHops = params.state.hops >= 15;
|
|
224
|
-
if (params.state.chunkLevel > 3 || approachingMaxHops) {
|
|
225
|
-
newChunksToQuery.length = 0;
|
|
226
|
-
nextStep = "answer";
|
|
227
|
-
}
|
|
228
|
-
const returnedHops = params.state.hops + 1;
|
|
85
|
+
});
|
|
229
86
|
return {
|
|
230
|
-
hops:
|
|
87
|
+
hops: params.state.hops + 1,
|
|
88
|
+
llmCalls: 0,
|
|
231
89
|
notebook: newNotebookEntries,
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
status: statuses.filter((status) => status),
|
|
237
|
-
tokens: tokenUsed,
|
|
90
|
+
processedChunks: fetched.map((chunk) => chunk.id),
|
|
91
|
+
queuedChunks: [],
|
|
92
|
+
nextStep: params.state.neighbouringAlreadyExplored ? "answer" : "neighbouring_nodes",
|
|
93
|
+
tokens: { input: 0, output: 0 },
|
|
238
94
|
};
|
|
239
95
|
}
|
|
240
96
|
};
|
|
241
97
|
exports.ChunkNodeService = ChunkNodeService;
|
|
242
98
|
exports.ChunkNodeService = ChunkNodeService = ChunkNodeService_1 = __decorate([
|
|
243
99
|
(0, common_1.Injectable)(),
|
|
244
|
-
|
|
245
|
-
__param(5, (0, common_1.Inject)(retrieval_source_interface_1.CONTEXTUALISER_TOOLS)),
|
|
246
|
-
__metadata("design:paramtypes", [llm_service_1.LLMService,
|
|
247
|
-
chunk_repository_1.ChunkRepository,
|
|
248
|
-
websocket_service_1.WebSocketService,
|
|
249
|
-
nestjs_cls_1.ClsService,
|
|
250
|
-
config_1.ConfigService, Array])
|
|
100
|
+
__metadata("design:paramtypes", [chunk_repository_1.ChunkRepository])
|
|
251
101
|
], ChunkNodeService);
|
|
252
102
|
//# sourceMappingURL=chunk.node.service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk.node.service.js","sourceRoot":"","sources":["../../../../src/agents/contextualiser/nodes/chunk.node.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chunk.node.service.js","sourceRoot":"","sources":["../../../../src/agents/contextualiser/nodes/chunk.node.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ClsService } from "nestjs-cls";
|
|
3
|
-
import { BaseConfigInterface } from "../../../config/interfaces";
|
|
4
|
-
import { LLMService } from "../../../core/llm/services/llm.service";
|
|
5
|
-
import { WebSocketService } from "../../../core/websocket/services/websocket.service";
|
|
1
|
+
import { EmbedderService } from "../../../core/llm/services/embedder.service";
|
|
6
2
|
import { ChunkRepository } from "../../../foundations/chunk/repositories/chunk.repository";
|
|
7
3
|
import { ContextualiserContext, ContextualiserContextState } from "../../contextualiser/contexts/contextualiser.context";
|
|
8
4
|
import { RetrievalSourceContribution } from "../interfaces/retrieval.source.interface";
|
|
9
|
-
export declare const defaultChunkVectorPrompt = "\nAs an intelligent assistant, your primary objective is to assess a specific **text chunk** and determine whether the available information suffices to answer the question.\n\nGiven the **question**, and the **rational plan** to answer the question you have to:\n1. Write a note summarizing the key points from the current text chunk that are relevant to the question. This must be used as context to answer the question.\n - The note should contain all the information required to provide a detailed answer\n - It should be a comprehensive note that can be used to generate a precise, contextualise reponse to the question, containing all the required details enough to cover all relevant aspects.\n\n2. Write a reason describing how the text chunk is relevant to the question\n - The reason should explain why the text chunk is relevant or not to answer the question.\n\n3. Select the appropriate next action to take based on your assessment of the current information.\n - **queuePreviousChunk**: Choose this action if you feel that the current chunk of text might have relevant information in a previous text chunk that would **significantly** enhance your answer.\n - **queueNextChunk**: Choose this action if you feel that the current chunk of text might have relevant information in a subsequent text chunk that would **significantly** enhance your answer.\n - **readNeighbouringNodes**: Choose this action if you believe that this text chunk does not contain relevant information and that exploring neighbouring chunks could provide valuable context.\n - **answer**: Choose this action if you believe that the information in this text chunk is sufficient to provide a **comprehensive and accurate** answer to the question.\n\n 4. **Provide a Status Message**:\n - Write a **short, friendly message** (maximum 40 characters) about your action.\n - **Avoid technical terms** such as \"nodes\", \"atomic facts\", or \"key concepts\".\n - The status message should make the user understand the action being taken\n - The status message **MUST** contain clear information contextualised to the current question and the gathered information.\n - The status message should be specific to the context and clearly convey the next steps or actions being taken.\n - The status message **MUST NOT** be something unrelated to the text, such as \"success\", \"sufficient information\", \"insufficient information\", \"chunk analysed\", \"chunk processed\" or similar generic messages.\n \n ### Important Notes:\n - **Proceed to Answer When Appropriate**: If the current information is sufficient to provide a reliable answer, do not hesitate to proceed to select **answer** as the next step.\n - **Gather More Information When Needed**: If you identify gaps or uncertainties that could be addressed by additional information, choose the appropriate action to gather that information.\n - **Use Judgment in Decision-Making**: Apply thoughtful consideration to decide whether additional information is necessary.\n - If the content contains acronyms and their definition, include the definition of the acronym in your answer.\n \n### **Please strictly follow the above instructions and format. Let's begin.**\n";
|
|
10
5
|
export declare class ChunkVectorNodeService {
|
|
11
|
-
private readonly llmService;
|
|
12
6
|
private readonly chunkRepository;
|
|
13
|
-
private readonly
|
|
14
|
-
private readonly clsService;
|
|
15
|
-
private readonly configService;
|
|
7
|
+
private readonly embedderService;
|
|
16
8
|
private readonly retrievalSources?;
|
|
17
9
|
private readonly logger;
|
|
18
|
-
|
|
19
|
-
constructor(llmService: LLMService, chunkRepository: ChunkRepository, webSocketService: WebSocketService, clsService: ClsService, configService: ConfigService<BaseConfigInterface>, retrievalSources?: RetrievalSourceContribution[]);
|
|
10
|
+
constructor(chunkRepository: ChunkRepository, embedderService: EmbedderService, retrievalSources?: RetrievalSourceContribution[]);
|
|
20
11
|
execute(params: {
|
|
21
12
|
state: typeof ContextualiserContext.State;
|
|
22
13
|
}): Promise<Partial<ContextualiserContextState>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk.vector.node.service.d.ts","sourceRoot":"","sources":["../../../../src/agents/contextualiser/nodes/chunk.vector.node.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"chunk.vector.node.service.d.ts","sourceRoot":"","sources":["../../../../src/agents/contextualiser/nodes/chunk.vector.node.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,0DAA0D,CAAC;AAE3F,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC3B,MAAM,sDAAsD,CAAC;AAE9D,OAAO,EAAqB,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AAI1G,qBACa,sBAAsB;IAI/B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAGhC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAPpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;gBAG/C,eAAe,EAAE,eAAe,EAChC,eAAe,EAAE,eAAe,EAGhC,gBAAgB,CAAC,EAAE,2BAA2B,EAAE;IAG7D,OAAO,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,qBAAqB,CAAC,KAAK,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;CA8GnH"}
|
|
@@ -13,92 +13,39 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
13
13
|
};
|
|
14
14
|
var ChunkVectorNodeService_1;
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.ChunkVectorNodeService =
|
|
16
|
+
exports.ChunkVectorNodeService = void 0;
|
|
17
17
|
const common_1 = require("@nestjs/common");
|
|
18
|
-
const
|
|
19
|
-
const nestjs_cls_1 = require("nestjs-cls");
|
|
20
|
-
const zod_1 = require("zod");
|
|
21
|
-
const llm_service_1 = require("../../../core/llm/services/llm.service");
|
|
22
|
-
const websocket_service_1 = require("../../../core/websocket/services/websocket.service");
|
|
18
|
+
const embedder_service_1 = require("../../../core/llm/services/embedder.service");
|
|
23
19
|
const chunk_repository_1 = require("../../../foundations/chunk/repositories/chunk.repository");
|
|
24
20
|
const usage_attribution_1 = require("../../common/usage-attribution");
|
|
25
21
|
const retrieval_source_interface_1 = require("../interfaces/retrieval.source.interface");
|
|
26
22
|
const NEIGHBOR_WINDOW = 1;
|
|
27
|
-
exports.defaultChunkVectorPrompt = `
|
|
28
|
-
As an intelligent assistant, your primary objective is to assess a specific **text chunk** and determine whether the available information suffices to answer the question.
|
|
29
|
-
|
|
30
|
-
Given the **question**, and the **rational plan** to answer the question you have to:
|
|
31
|
-
1. Write a note summarizing the key points from the current text chunk that are relevant to the question. This must be used as context to answer the question.
|
|
32
|
-
- The note should contain all the information required to provide a detailed answer
|
|
33
|
-
- It should be a comprehensive note that can be used to generate a precise, contextualise reponse to the question, containing all the required details enough to cover all relevant aspects.
|
|
34
|
-
|
|
35
|
-
2. Write a reason describing how the text chunk is relevant to the question
|
|
36
|
-
- The reason should explain why the text chunk is relevant or not to answer the question.
|
|
37
|
-
|
|
38
|
-
3. Select the appropriate next action to take based on your assessment of the current information.
|
|
39
|
-
- **queuePreviousChunk**: Choose this action if you feel that the current chunk of text might have relevant information in a previous text chunk that would **significantly** enhance your answer.
|
|
40
|
-
- **queueNextChunk**: Choose this action if you feel that the current chunk of text might have relevant information in a subsequent text chunk that would **significantly** enhance your answer.
|
|
41
|
-
- **readNeighbouringNodes**: Choose this action if you believe that this text chunk does not contain relevant information and that exploring neighbouring chunks could provide valuable context.
|
|
42
|
-
- **answer**: Choose this action if you believe that the information in this text chunk is sufficient to provide a **comprehensive and accurate** answer to the question.
|
|
43
|
-
|
|
44
|
-
4. **Provide a Status Message**:
|
|
45
|
-
- Write a **short, friendly message** (maximum 40 characters) about your action.
|
|
46
|
-
- **Avoid technical terms** such as "nodes", "atomic facts", or "key concepts".
|
|
47
|
-
- The status message should make the user understand the action being taken
|
|
48
|
-
- The status message **MUST** contain clear information contextualised to the current question and the gathered information.
|
|
49
|
-
- The status message should be specific to the context and clearly convey the next steps or actions being taken.
|
|
50
|
-
- The status message **MUST NOT** be something unrelated to the text, such as "success", "sufficient information", "insufficient information", "chunk analysed", "chunk processed" or similar generic messages.
|
|
51
|
-
|
|
52
|
-
### Important Notes:
|
|
53
|
-
- **Proceed to Answer When Appropriate**: If the current information is sufficient to provide a reliable answer, do not hesitate to proceed to select **answer** as the next step.
|
|
54
|
-
- **Gather More Information When Needed**: If you identify gaps or uncertainties that could be addressed by additional information, choose the appropriate action to gather that information.
|
|
55
|
-
- **Use Judgment in Decision-Making**: Apply thoughtful consideration to decide whether additional information is necessary.
|
|
56
|
-
- If the content contains acronyms and their definition, include the definition of the acronym in your answer.
|
|
57
|
-
|
|
58
|
-
### **Please strictly follow the above instructions and format. Let's begin.**
|
|
59
|
-
`;
|
|
60
|
-
const outputSchema = zod_1.z.object({
|
|
61
|
-
status: zod_1.z
|
|
62
|
-
.string()
|
|
63
|
-
.describe(`Write a short, friendly message (max 40 characters) about your action, avoiding technical terms such as "nodes" or "atomic facts" or "key concepts". Give flavour to the message and avoid repeating the same message.`),
|
|
64
|
-
note: zod_1.z
|
|
65
|
-
.object({
|
|
66
|
-
content: zod_1.z.string().describe("The new insights and findings about the question from current text"),
|
|
67
|
-
reason: zod_1.z.string().describe("The reason describing how the text chunk is relevant to the question"),
|
|
68
|
-
})
|
|
69
|
-
.describe("The note summarizing the key points from the current text chunk that are relevant to the question"),
|
|
70
|
-
chosenAction: zod_1.z.string()
|
|
71
|
-
.describe(`This is the action you have decided to do in the next step. You **MUST** pick one of the following actions:
|
|
72
|
-
- **queuePreviousChunk**: Choose this action if you feel that the previous text chunk contains valuable information for answering the question.
|
|
73
|
-
- **queueNextChunk**: Choose this action if you feel that the subsequent text chunk contains valuable information for answering the question.
|
|
74
|
-
- **readNeighbouringNodes**: Choose this action if you feel that the current text contains valuable, but somewhat incomplete information that could be clarified by exploring related concepts.
|
|
75
|
-
- **answer**: Choose this action if you believe that the information you have currently obtained is enough to answer the question. This will allow you to summarize the gathered information and provide a final answer.
|
|
76
|
-
`),
|
|
77
|
-
});
|
|
78
|
-
const inputSchema = zod_1.z.object({
|
|
79
|
-
question: zod_1.z.string().describe("The question asked by the user"),
|
|
80
|
-
rationalPlan: zod_1.z
|
|
81
|
-
.string()
|
|
82
|
-
.describe("The rational plan you designed to provide a comprehensive answer to the user question"),
|
|
83
|
-
text: zod_1.z.string().describe("The content of the text you must analyse to provide an answer to the user question"),
|
|
84
|
-
});
|
|
85
23
|
let ChunkVectorNodeService = ChunkVectorNodeService_1 = class ChunkVectorNodeService {
|
|
86
|
-
constructor(
|
|
87
|
-
this.llmService = llmService;
|
|
24
|
+
constructor(chunkRepository, embedderService, retrievalSources) {
|
|
88
25
|
this.chunkRepository = chunkRepository;
|
|
89
|
-
this.
|
|
90
|
-
this.clsService = clsService;
|
|
91
|
-
this.configService = configService;
|
|
26
|
+
this.embedderService = embedderService;
|
|
92
27
|
this.retrievalSources = retrievalSources;
|
|
93
28
|
this.logger = new common_1.Logger(ChunkVectorNodeService_1.name);
|
|
94
|
-
const prompts = this.configService.get("prompts");
|
|
95
|
-
this.systemPrompt = prompts?.contextualiser?.chunkVector ?? exports.defaultChunkVectorPrompt;
|
|
96
29
|
}
|
|
97
30
|
async execute(params) {
|
|
31
|
+
// ONE embedding per turn. findPotentialChunks and findPotentialKeyConcepts
|
|
32
|
+
// were each embedding the identical question string, costing two provider
|
|
33
|
+
// round trips and two ledger rows for one question.
|
|
34
|
+
const queryEmbedding = params.state.questionEmbedding ??
|
|
35
|
+
(await this.embedderService.vectoriseText({
|
|
36
|
+
text: params.state.question,
|
|
37
|
+
attribution: (0, usage_attribution_1.buildRetrievalAttribution)({
|
|
38
|
+
contentId: params.state.contentId,
|
|
39
|
+
contentType: params.state.contentType,
|
|
40
|
+
dataLimits: params.state.limits,
|
|
41
|
+
scope: params.state,
|
|
42
|
+
}),
|
|
43
|
+
}));
|
|
98
44
|
const [chunks, contributed] = await Promise.all([
|
|
99
45
|
this.chunkRepository.findPotentialChunks({
|
|
100
46
|
question: params.state.question,
|
|
101
47
|
dataLimits: params.state.limits,
|
|
48
|
+
queryEmbedding,
|
|
102
49
|
// The question embedding is billed to the scope this retrieval searches.
|
|
103
50
|
// Task 10 threaded the CALLING agent's own attribution through this
|
|
104
51
|
// state, and it is now the first branch of the derivation: when another
|
|
@@ -123,8 +70,9 @@ let ChunkVectorNodeService = ChunkVectorNodeService_1 = class ChunkVectorNodeSer
|
|
|
123
70
|
return [];
|
|
124
71
|
}))).then((lists) => lists.flat()),
|
|
125
72
|
]);
|
|
126
|
-
// Neighbour-window widening: each retrieved chunk
|
|
127
|
-
//
|
|
73
|
+
// Neighbour-window widening: each retrieved chunk carries the chunks
|
|
74
|
+
// immediately before/after it, so what reaches the notebook is continuous
|
|
75
|
+
// prose rather than a sentence cut at both ends.
|
|
128
76
|
const allRetrievedIds = chunks.map((c) => c.id);
|
|
129
77
|
const neighborRecords = allRetrievedIds.length
|
|
130
78
|
? await this.chunkRepository.findChunkNeighbors({ chunkIds: allRetrievedIds, window: NEIGHBOR_WINDOW })
|
|
@@ -138,63 +86,26 @@ let ChunkVectorNodeService = ChunkVectorNodeService_1 = class ChunkVectorNodeSer
|
|
|
138
86
|
};
|
|
139
87
|
if (chunks.length === 0 && contributed.length === 0) {
|
|
140
88
|
this.logger.log("chunk_vector: no results — continuing per rational plan routing");
|
|
141
|
-
|
|
89
|
+
// Nothing to analyse: this path makes no provider call.
|
|
90
|
+
return { llmCalls: 0, questionEmbedding: queryEmbedding };
|
|
142
91
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
rationalPlan: params.state.rationalPlan,
|
|
148
|
-
question: params.state.question,
|
|
149
|
-
text: widen(chunk.id, chunk.content),
|
|
150
|
-
};
|
|
151
|
-
const llmResponse = await this.llmService.call({
|
|
152
|
-
inputSchema: inputSchema,
|
|
153
|
-
inputParams: inputParams,
|
|
154
|
-
outputSchema: outputSchema,
|
|
155
|
-
systemPrompts: [this.systemPrompt],
|
|
156
|
-
temperature: 0.1,
|
|
157
|
-
// Billed to the CALLING agent: its ledger category, its entity. Spread
|
|
158
|
-
// LAST so nothing above can overwrite the attribution.
|
|
159
|
-
...(0, usage_attribution_1.buildInheritedAttribution)(params.state),
|
|
160
|
-
});
|
|
161
|
-
if (params.state.contentType === "Conversation")
|
|
162
|
-
await this.webSocketService.sendMessageToUser(this.clsService.get("userId"), "contextualiser", {
|
|
163
|
-
message: llmResponse.status,
|
|
164
|
-
conversationId: params.state.contentId,
|
|
165
|
-
});
|
|
166
|
-
return {
|
|
167
|
-
chunkId: chunk.id,
|
|
168
|
-
status: llmResponse.status,
|
|
169
|
-
note: {
|
|
170
|
-
content: llmResponse.note?.content ?? "",
|
|
171
|
-
reason: llmResponse.note?.reason ?? "",
|
|
172
|
-
},
|
|
173
|
-
chosenAction: llmResponse.chosenAction,
|
|
174
|
-
tokens: llmResponse.tokenUsage,
|
|
175
|
-
};
|
|
176
|
-
})));
|
|
177
|
-
const tokenUsed = {
|
|
178
|
-
input: 0,
|
|
179
|
-
output: 0,
|
|
180
|
-
};
|
|
92
|
+
// No per-chunk LLM call. It filtered nothing — the notebook push was
|
|
93
|
+
// unconditional — and its paraphrase REPLACED the chunk, so the answer node
|
|
94
|
+
// never saw text it could quote. The widened source text goes through
|
|
95
|
+
// instead, ordered and budgeted downstream (responder.answer.node.service).
|
|
181
96
|
const newNotebookEntries = [];
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
tokenUsed.output += llmResponse.tokens.output;
|
|
97
|
+
for (const chunk of chunks) {
|
|
98
|
+
if (!chunk.content || chunk.content.trim() === "")
|
|
99
|
+
continue;
|
|
186
100
|
newNotebookEntries.push({
|
|
187
|
-
chunkId:
|
|
188
|
-
content:
|
|
189
|
-
reason:
|
|
101
|
+
chunkId: chunk.id,
|
|
102
|
+
content: widen(chunk.id, chunk.content),
|
|
103
|
+
reason: "",
|
|
190
104
|
sourceLayer: "case",
|
|
191
105
|
metadata: undefined,
|
|
106
|
+
score: chunk.score,
|
|
107
|
+
coreContent: chunk.content,
|
|
192
108
|
});
|
|
193
|
-
if (llmResponse.status &&
|
|
194
|
-
!statuses.includes(llmResponse.status) &&
|
|
195
|
-
!params.state.status.includes(llmResponse.status)) {
|
|
196
|
-
statuses.push(llmResponse.status);
|
|
197
|
-
}
|
|
198
109
|
}
|
|
199
110
|
for (const entry of contributed) {
|
|
200
111
|
newNotebookEntries.push({
|
|
@@ -203,26 +114,26 @@ let ChunkVectorNodeService = ChunkVectorNodeService_1 = class ChunkVectorNodeSer
|
|
|
203
114
|
reason: entry.reason,
|
|
204
115
|
sourceLayer: entry.sourceLayer ?? "case",
|
|
205
116
|
metadata: entry.metadata,
|
|
117
|
+
score: undefined,
|
|
118
|
+
coreContent: undefined,
|
|
206
119
|
});
|
|
207
120
|
}
|
|
208
121
|
return {
|
|
209
122
|
hops: params.state.hops + 1,
|
|
123
|
+
llmCalls: 0,
|
|
210
124
|
processedChunks: chunks.map((c) => c.id),
|
|
211
125
|
notebook: newNotebookEntries,
|
|
212
|
-
|
|
213
|
-
tokens:
|
|
126
|
+
questionEmbedding: queryEmbedding,
|
|
127
|
+
tokens: { input: 0, output: 0 },
|
|
214
128
|
};
|
|
215
129
|
}
|
|
216
130
|
};
|
|
217
131
|
exports.ChunkVectorNodeService = ChunkVectorNodeService;
|
|
218
132
|
exports.ChunkVectorNodeService = ChunkVectorNodeService = ChunkVectorNodeService_1 = __decorate([
|
|
219
133
|
(0, common_1.Injectable)(),
|
|
220
|
-
__param(
|
|
221
|
-
__param(
|
|
222
|
-
__metadata("design:paramtypes", [
|
|
223
|
-
|
|
224
|
-
websocket_service_1.WebSocketService,
|
|
225
|
-
nestjs_cls_1.ClsService,
|
|
226
|
-
config_1.ConfigService, Array])
|
|
134
|
+
__param(2, (0, common_1.Optional)()),
|
|
135
|
+
__param(2, (0, common_1.Inject)(retrieval_source_interface_1.RETRIEVAL_SOURCES)),
|
|
136
|
+
__metadata("design:paramtypes", [chunk_repository_1.ChunkRepository,
|
|
137
|
+
embedder_service_1.EmbedderService, Array])
|
|
227
138
|
], ChunkVectorNodeService);
|
|
228
139
|
//# sourceMappingURL=chunk.vector.node.service.js.map
|