noteconnection 1.6.8 → 1.8.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 (212) hide show
  1. package/LICENSE +674 -21
  2. package/README.md +258 -64
  3. package/dist/src/agent_workspace.contract.parity.test.js +475 -0
  4. package/dist/src/agent_workspace.frontend.test.js +9989 -0
  5. package/dist/src/agent_workspace.locale.contract.test.js +95 -0
  6. package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
  7. package/dist/src/copy.assets.contract.test.js +130 -0
  8. package/dist/src/core/PathBridge.js +28 -3
  9. package/dist/src/export/WorkspaceExportBundle.js +1130 -0
  10. package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
  11. package/dist/src/export/index.js +18 -0
  12. package/dist/src/export/types.js +2 -0
  13. package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
  14. package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
  15. package/dist/src/foundation.release.evidence.contract.test.js +406 -0
  16. package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
  17. package/dist/src/frontend/README.md +258 -64
  18. package/dist/src/frontend/agent_workspace.js +5353 -0
  19. package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
  20. package/dist/src/frontend/analysis.js +31 -4
  21. package/dist/src/frontend/app.js +3597 -141
  22. package/dist/src/frontend/focus_mode_interactions.js +33 -0
  23. package/dist/src/frontend/godot_future_path_renderer.js +540 -0
  24. package/dist/src/frontend/godot_tree_interactions.js +178 -0
  25. package/dist/src/frontend/graph_state.mjs +105 -0
  26. package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
  27. package/dist/src/frontend/i18n.mjs +186 -0
  28. package/dist/src/frontend/index.html +641 -266
  29. package/dist/src/frontend/layout_gpu.js +12 -4
  30. package/dist/src/frontend/locales/en.json +721 -5
  31. package/dist/src/frontend/locales/zh.json +721 -5
  32. package/dist/src/frontend/main.mjs +60 -0
  33. package/dist/src/frontend/markdown_runtime.js +827 -0
  34. package/dist/src/frontend/notemd.css +49 -0
  35. package/dist/src/frontend/notemd.html +7 -1
  36. package/dist/src/frontend/notemd.js +64 -0
  37. package/dist/src/frontend/path.html +107 -0
  38. package/dist/src/frontend/path_app.js +2189 -150
  39. package/dist/src/frontend/path_layout.mjs +143 -0
  40. package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
  41. package/dist/src/frontend/path_modules_bridge.js +486 -0
  42. package/dist/src/frontend/path_state.mjs +118 -0
  43. package/dist/src/frontend/path_styles.css +146 -0
  44. package/dist/src/frontend/path_worker_bridge.mjs +85 -0
  45. package/dist/src/frontend/reader.js +522 -27
  46. package/dist/src/frontend/runtime_bridge.js +67 -54
  47. package/dist/src/frontend/runtime_bridge.mjs +279 -0
  48. package/dist/src/frontend/settings.js +130 -12
  49. package/dist/src/frontend/simulationWorker.js +241 -6
  50. package/dist/src/frontend/source_manager.js +190 -21
  51. package/dist/src/frontend/styles.css +2853 -72
  52. package/dist/src/frontend/workbench_state.mjs +101 -0
  53. package/dist/src/frontend/workspace_panes.js +10168 -0
  54. package/dist/src/frontend.locale.contract.test.js +62 -0
  55. package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
  56. package/dist/src/indexing/IndexLifecycle.js +195 -0
  57. package/dist/src/indexing/IndexLifecycle.test.js +49 -0
  58. package/dist/src/indexing/SegmentBuilder.js +64 -0
  59. package/dist/src/indexing/UnitBuilder.js +48 -0
  60. package/dist/src/indexing/types.js +2 -0
  61. package/dist/src/knowledge.api.contract.test.js +170 -0
  62. package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
  63. package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
  64. package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
  65. package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
  66. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
  67. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
  68. package/dist/src/learning/answerReleaseReview.js +4319 -0
  69. package/dist/src/learning/answerReleaseReview.test.js +2888 -0
  70. package/dist/src/learning/api.js +2 -0
  71. package/dist/src/learning/conversationComposer.js +1480 -0
  72. package/dist/src/learning/conversationComposer.test.js +1817 -0
  73. package/dist/src/learning/domains/ConversationManager.js +53 -0
  74. package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
  75. package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
  76. package/dist/src/learning/domains/MasteryEngine.js +387 -0
  77. package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
  78. package/dist/src/learning/domains/QualityEvaluator.js +307 -0
  79. package/dist/src/learning/domains/TutorRouter.js +313 -0
  80. package/dist/src/learning/domains/index.js +33 -0
  81. package/dist/src/learning/domains/types.js +7 -0
  82. package/dist/src/learning/errors.js +29 -0
  83. package/dist/src/learning/evidenceContextAssembler.js +1176 -0
  84. package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
  85. package/dist/src/learning/graphContextAssembler.js +870 -0
  86. package/dist/src/learning/graphContextAssembler.test.js +1033 -0
  87. package/dist/src/learning/index.js +28 -0
  88. package/dist/src/learning/queryBackend.js +1898 -0
  89. package/dist/src/learning/queryBackend.test.js +955 -0
  90. package/dist/src/learning/ragContextPack.js +257 -0
  91. package/dist/src/learning/ragContextPack.test.js +160 -0
  92. package/dist/src/learning/ragPublicText.js +38 -0
  93. package/dist/src/learning/ragSufficiencyJudge.js +161 -0
  94. package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
  95. package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
  96. package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
  97. package/dist/src/learning/requestNormalization.js +198 -0
  98. package/dist/src/learning/runtimeCapability.js +4677 -0
  99. package/dist/src/learning/runtimeCapability.test.js +3635 -0
  100. package/dist/src/learning/store.js +1240 -0
  101. package/dist/src/learning/store.test.js +1126 -0
  102. package/dist/src/learning/tutorAdapter.js +2 -0
  103. package/dist/src/learning/types.js +2 -0
  104. package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
  105. package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
  106. package/dist/src/lfs.asset.policy.contract.test.js +153 -0
  107. package/dist/src/license.policy.contract.test.js +66 -0
  108. package/dist/src/memory/MemoryGovernance.js +74 -0
  109. package/dist/src/memory/MemoryGovernance.test.js +46 -0
  110. package/dist/src/memory/types.js +2 -0
  111. package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
  112. package/dist/src/middleware/auth.js +17 -0
  113. package/dist/src/middleware/body-parser.js +45 -0
  114. package/dist/src/middleware/cors.js +44 -0
  115. package/dist/src/middleware/index.js +21 -0
  116. package/dist/src/middleware/request-trace.js +96 -0
  117. package/dist/src/notemd/AppConfigToml.js +6 -4
  118. package/dist/src/notemd/MermaidProcessor.js +400 -50
  119. package/dist/src/notemd/NotemdService.js +498 -13
  120. package/dist/src/notemd/PromptManager.js +15 -0
  121. package/dist/src/notemd/cli/commands.js +357 -0
  122. package/dist/src/notemd/cli/dispatcher.js +225 -0
  123. package/dist/src/notemd/cli/index.js +169 -0
  124. package/dist/src/notemd/cli/parser.js +68 -0
  125. package/dist/src/notemd/cli/types.js +2 -0
  126. package/dist/src/notemd/constants.js +43 -0
  127. package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
  128. package/dist/src/notemd/diagram/diagramSpec.js +79 -0
  129. package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
  130. package/dist/src/notemd/diagram/intent.js +95 -0
  131. package/dist/src/notemd/diagram/planner.js +71 -0
  132. package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
  133. package/dist/src/notemd/diagram/types.js +18 -0
  134. package/dist/src/notemd/index.js +26 -0
  135. package/dist/src/notemd/operations/capabilityManifest.js +23 -0
  136. package/dist/src/notemd/operations/cliContracts.js +17 -0
  137. package/dist/src/notemd/operations/configProfileCommands.js +85 -0
  138. package/dist/src/notemd/operations/registry.contract.test.js +95 -0
  139. package/dist/src/notemd/operations/registry.js +991 -0
  140. package/dist/src/notemd/operations/types.js +2 -0
  141. package/dist/src/notemd/providerDiagnostics.js +220 -0
  142. package/dist/src/notemd/providerProfiles.js +42 -0
  143. package/dist/src/notemd/providerTemplates.js +231 -0
  144. package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
  145. package/dist/src/notemd/search/SearchManager.js +13 -0
  146. package/dist/src/notemd/search/SearchProvider.js +2 -0
  147. package/dist/src/notemd/search/TavilyProvider.js +44 -0
  148. package/dist/src/notemd.agent.manifest.test.js +85 -0
  149. package/dist/src/notemd.api.contract.test.js +14 -1
  150. package/dist/src/notemd.app_config_toml.test.js +2 -1
  151. package/dist/src/notemd.batch.workflow.test.js +117 -0
  152. package/dist/src/notemd.cli.e2e.test.js +136 -0
  153. package/dist/src/notemd.core.test.js +51 -0
  154. package/dist/src/notemd.diagram.pipeline.test.js +233 -0
  155. package/dist/src/notemd.providerTemplates.test.js +34 -0
  156. package/dist/src/notemd.server.integration.test.js +143 -35
  157. package/dist/src/notemd.workflow.pipeline.test.js +162 -0
  158. package/dist/src/pathbridge.handshake.contract.test.js +16 -2
  159. package/dist/src/pathmode.background.contract.test.js +69 -0
  160. package/dist/src/pathmode.settings.api.contract.test.js +9 -0
  161. package/dist/src/pkg.sidecar.contract.test.js +9 -3
  162. package/dist/src/platform/ExportProfile.js +58 -0
  163. package/dist/src/platform/PlatformCapabilities.js +45 -0
  164. package/dist/src/platform/PlatformCapabilities.test.js +30 -0
  165. package/dist/src/platform/RenderMaterializer.js +33 -0
  166. package/dist/src/platform/RenderMaterializer.test.js +32 -0
  167. package/dist/src/query_backend.external_http.integration.test.js +410 -0
  168. package/dist/src/reader_renderer.js +404 -3
  169. package/dist/src/reader_renderer.test.js +87 -0
  170. package/dist/src/release.godot.mirror.contract.test.js +73 -0
  171. package/dist/src/resources/ResourceRegistry.js +223 -0
  172. package/dist/src/resources/ResourceRegistry.test.js +61 -0
  173. package/dist/src/resources/types.js +2 -0
  174. package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
  175. package/dist/src/routes/data.js +267 -0
  176. package/dist/src/routes/diagnostics.js +51 -0
  177. package/dist/src/routes/index.js +23 -0
  178. package/dist/src/routes/knowledge.js +968 -0
  179. package/dist/src/routes/markdown.js +287 -0
  180. package/dist/src/routes/notemd.js +565 -0
  181. package/dist/src/routes/registry.contract.test.js +130 -0
  182. package/dist/src/routes/render.js +285 -0
  183. package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
  184. package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
  185. package/dist/src/routes/settings.js +6 -0
  186. package/dist/src/routes/staticFiles.js +94 -0
  187. package/dist/src/routes/types.js +2 -0
  188. package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
  189. package/dist/src/server.js +11090 -1549
  190. package/dist/src/server.migration.test.js +193 -21
  191. package/dist/src/server.port.fallback.contract.test.js +63 -0
  192. package/dist/src/session/SessionStateStore.js +81 -0
  193. package/dist/src/session/SessionStateStore.test.js +58 -0
  194. package/dist/src/session/types.js +2 -0
  195. package/dist/src/settings.runtime.contract.test.js +50 -0
  196. package/dist/src/shared/types.contract.test.js +107 -0
  197. package/dist/src/shared/types.js +22 -0
  198. package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
  199. package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
  200. package/dist/src/source_manager.loadflow.test.js +46 -0
  201. package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
  202. package/dist/src/tauri.frontend.build.contract.test.js +60 -0
  203. package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
  204. package/dist/src/utils/RuntimePaths.js +4 -13
  205. package/dist/src/utils/platform.js +153 -0
  206. package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
  207. package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
  208. package/dist/src/workflows/types.js +2 -0
  209. package/dist/src/workspace/WorkspaceRegistry.js +122 -0
  210. package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
  211. package/dist/src/workspace/types.js +2 -0
  212. package/package.json +61 -10
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_RAG_CONTEXT_BUDGET = void 0;
4
+ exports.normalizeRagContextBudget = normalizeRagContextBudget;
5
+ exports.estimateRagTokenCount = estimateRagTokenCount;
6
+ exports.buildRagContextPack = buildRagContextPack;
7
+ const crypto_1 = require("crypto");
8
+ exports.DEFAULT_RAG_CONTEXT_BUDGET = {
9
+ maxFragments: 16,
10
+ maxCharsPerFragment: 1600,
11
+ maxTotalChars: 6400,
12
+ };
13
+ const ROLE_PRIORITY = {
14
+ direct_support: 0,
15
+ conflict: 1,
16
+ graph_neighbor_support: 2,
17
+ parent_context: 3,
18
+ adjacent_context: 4,
19
+ background: 5,
20
+ };
21
+ function normalizeRagContextBudget(input) {
22
+ const numberOrDefault = (value, fallback, min, max) => {
23
+ const numeric = Number(value);
24
+ if (!Number.isFinite(numeric)) {
25
+ return fallback;
26
+ }
27
+ return Math.floor(Math.max(min, Math.min(max, numeric)));
28
+ };
29
+ return {
30
+ maxFragments: numberOrDefault(input?.maxFragments, exports.DEFAULT_RAG_CONTEXT_BUDGET.maxFragments, 1, 200),
31
+ maxCharsPerFragment: numberOrDefault(input?.maxCharsPerFragment, exports.DEFAULT_RAG_CONTEXT_BUDGET.maxCharsPerFragment, 80, 20000),
32
+ maxTotalChars: numberOrDefault(input?.maxTotalChars, exports.DEFAULT_RAG_CONTEXT_BUDGET.maxTotalChars, 120, 100000),
33
+ };
34
+ }
35
+ function estimateRagTokenCount(text) {
36
+ const normalized = String(text || '').trim();
37
+ if (!normalized) {
38
+ return 0;
39
+ }
40
+ return Math.max(1, Math.ceil(normalized.length / 4));
41
+ }
42
+ function truncateMiddle(text, maxChars) {
43
+ const source = String(text || '');
44
+ if (source.length <= maxChars) {
45
+ return { text: source, truncated: false };
46
+ }
47
+ if (maxChars <= 16) {
48
+ return { text: source.slice(0, maxChars), truncated: true };
49
+ }
50
+ const marker = '\n[...]\n';
51
+ const available = Math.max(0, maxChars - marker.length);
52
+ const headLength = Math.ceil(available * 0.6);
53
+ const tailLength = Math.floor(available * 0.4);
54
+ return {
55
+ text: `${source.slice(0, headLength).trimEnd()}${marker}${source.slice(source.length - tailLength).trimStart()}`,
56
+ truncated: true,
57
+ };
58
+ }
59
+ function withBudgetedText(fragment, maxChars, reason) {
60
+ const truncated = truncateMiddle(fragment.text, maxChars);
61
+ const text = truncated.text;
62
+ return {
63
+ ...fragment,
64
+ text,
65
+ charCount: text.length,
66
+ tokenEstimate: estimateRagTokenCount(text),
67
+ truncated: fragment.truncated || truncated.truncated,
68
+ truncationReason: truncated.truncated ? reason : fragment.truncationReason,
69
+ };
70
+ }
71
+ function rolePriority(fragment) {
72
+ return ROLE_PRIORITY[fragment.role] ?? ROLE_PRIORITY.background;
73
+ }
74
+ function sortFragmentsForBudget(fragments) {
75
+ return fragments
76
+ .map((fragment, index) => ({ fragment, index }))
77
+ .sort((a, b) => {
78
+ const priorityDelta = rolePriority(a.fragment) - rolePriority(b.fragment);
79
+ if (priorityDelta !== 0) {
80
+ return priorityDelta;
81
+ }
82
+ const scoreDelta = Number(b.fragment.score || 0) - Number(a.fragment.score || 0);
83
+ if (Math.abs(scoreDelta) > 0.0001) {
84
+ return scoreDelta;
85
+ }
86
+ return a.index - b.index;
87
+ })
88
+ .map((entry) => entry.fragment);
89
+ }
90
+ function applyContextBudget(fragments, budget, decisions) {
91
+ const selected = [];
92
+ let usedChars = 0;
93
+ sortFragmentsForBudget(fragments).forEach((fragment) => {
94
+ if (selected.length >= budget.maxFragments) {
95
+ decisions.push({
96
+ documentId: fragment.documentId,
97
+ sourcePath: fragment.sourcePath,
98
+ sourceBoundary: fragment.sourceBoundary,
99
+ status: 'fragment_dropped',
100
+ reason: 'max_fragments_exceeded',
101
+ });
102
+ return;
103
+ }
104
+ let candidate = withBudgetedText(fragment, budget.maxCharsPerFragment, 'max_chars_per_fragment_exceeded');
105
+ const remainingChars = budget.maxTotalChars - usedChars;
106
+ if (remainingChars <= 0) {
107
+ decisions.push({
108
+ documentId: fragment.documentId,
109
+ sourcePath: fragment.sourcePath,
110
+ sourceBoundary: fragment.sourceBoundary,
111
+ status: 'fragment_dropped',
112
+ reason: 'max_total_chars_exceeded',
113
+ });
114
+ return;
115
+ }
116
+ if (candidate.charCount > remainingChars) {
117
+ if (remainingChars < 80 && candidate.role !== 'direct_support') {
118
+ decisions.push({
119
+ documentId: fragment.documentId,
120
+ sourcePath: fragment.sourcePath,
121
+ sourceBoundary: fragment.sourceBoundary,
122
+ status: 'fragment_dropped',
123
+ reason: 'remaining_context_budget_too_small',
124
+ });
125
+ return;
126
+ }
127
+ candidate = withBudgetedText(candidate, remainingChars, 'max_total_chars_exceeded');
128
+ }
129
+ selected.push(candidate);
130
+ usedChars += candidate.charCount;
131
+ decisions.push({
132
+ documentId: candidate.documentId,
133
+ sourcePath: candidate.sourcePath,
134
+ sourceBoundary: candidate.sourceBoundary,
135
+ status: candidate.truncated ? 'fragment_truncated' : 'fragment_included',
136
+ reason: candidate.truncationReason,
137
+ });
138
+ });
139
+ return selected;
140
+ }
141
+ function resolveSourceBoundary(requestedBoundary, fragments) {
142
+ if (requestedBoundary) {
143
+ return requestedBoundary;
144
+ }
145
+ return fragments.some((fragment) => fragment.sourceBoundary === 'full_document')
146
+ ? 'full_document'
147
+ : 'direct_span_only';
148
+ }
149
+ function annotateReadDecisions(decisions, fragments) {
150
+ const fragmentCountsByDocument = fragments.reduce((counts, fragment) => {
151
+ const previous = counts.get(fragment.documentId) || 0;
152
+ counts.set(fragment.documentId, previous + 1);
153
+ return counts;
154
+ }, new Map());
155
+ decisions.forEach((decision) => {
156
+ if (decision.status === 'read') {
157
+ decision.fragmentsSelected = fragmentCountsByDocument.get(decision.documentId) || 0;
158
+ }
159
+ });
160
+ }
161
+ function sortedStrings(values) {
162
+ return normalizedStrings(values).sort();
163
+ }
164
+ function normalizedStrings(values) {
165
+ return (Array.isArray(values) ? values : [])
166
+ .map((value) => String(value || '').trim())
167
+ .filter(Boolean);
168
+ }
169
+ function buildRagContextReplayId(params) {
170
+ const payload = {
171
+ query: params.query,
172
+ sourceBoundary: params.sourceBoundary,
173
+ budget: params.budget,
174
+ totalCharCount: params.totalCharCount,
175
+ tokenEstimate: params.tokenEstimate,
176
+ fragments: params.fragments
177
+ .map((fragment) => ({
178
+ fragmentId: fragment.fragmentId,
179
+ role: fragment.role,
180
+ documentId: fragment.documentId,
181
+ sourcePath: fragment.sourcePath,
182
+ atomId: fragment.atomId || '',
183
+ title: fragment.title || '',
184
+ headingPath: normalizedStrings(fragment.headingPath),
185
+ citationIds: sortedStrings(fragment.citationIds),
186
+ relationEdgeIds: sortedStrings(fragment.relationEdgeIds),
187
+ sourceBoundary: fragment.sourceBoundary,
188
+ startOffset: fragment.startOffset ?? null,
189
+ endOffset: fragment.endOffset ?? null,
190
+ startLine: fragment.startLine ?? null,
191
+ endLine: fragment.endLine ?? null,
192
+ truncated: fragment.truncated,
193
+ truncationReason: fragment.truncationReason || '',
194
+ text: fragment.text,
195
+ }))
196
+ .sort((left, right) => [
197
+ left.role.localeCompare(right.role),
198
+ left.documentId.localeCompare(right.documentId),
199
+ left.fragmentId.localeCompare(right.fragmentId),
200
+ left.text.localeCompare(right.text),
201
+ ].find((delta) => delta !== 0) || 0),
202
+ sourceDecisions: params.sourceDecisions
203
+ .map((decision) => ({
204
+ documentId: decision.documentId,
205
+ sourcePath: decision.sourcePath,
206
+ sourceBoundary: decision.sourceBoundary,
207
+ status: decision.status,
208
+ reason: decision.reason || '',
209
+ charsRead: decision.charsRead ?? null,
210
+ fragmentsSelected: decision.fragmentsSelected ?? null,
211
+ }))
212
+ .sort((left, right) => [
213
+ left.documentId.localeCompare(right.documentId),
214
+ left.sourcePath.localeCompare(right.sourcePath),
215
+ left.sourceBoundary.localeCompare(right.sourceBoundary),
216
+ left.status.localeCompare(right.status),
217
+ left.reason.localeCompare(right.reason),
218
+ ].find((delta) => delta !== 0) || 0),
219
+ };
220
+ const digest = (0, crypto_1.createHash)('sha256')
221
+ .update(JSON.stringify(payload))
222
+ .digest('hex')
223
+ .slice(0, 16);
224
+ return `ragctx_${digest}`;
225
+ }
226
+ function buildRagContextPack(params) {
227
+ const budget = normalizeRagContextBudget(params.budget);
228
+ const decisions = Array.isArray(params.sourceDecisions)
229
+ ? params.sourceDecisions.map((decision) => ({ ...decision }))
230
+ : [];
231
+ const fragments = Array.isArray(params.fragments) ? params.fragments.filter(Boolean) : [];
232
+ const selectedFragments = applyContextBudget(fragments, budget, decisions);
233
+ annotateReadDecisions(decisions, selectedFragments);
234
+ const totalCharCount = selectedFragments.reduce((sum, fragment) => sum + fragment.charCount, 0);
235
+ const tokenEstimate = selectedFragments.reduce((sum, fragment) => sum + fragment.tokenEstimate, 0);
236
+ const query = String(params.query || '');
237
+ const sourceBoundary = resolveSourceBoundary(params.sourceBoundary, selectedFragments);
238
+ return {
239
+ replayId: buildRagContextReplayId({
240
+ query,
241
+ sourceBoundary,
242
+ budget,
243
+ fragments: selectedFragments,
244
+ sourceDecisions: decisions,
245
+ totalCharCount,
246
+ tokenEstimate,
247
+ }),
248
+ query,
249
+ generatedAt: String(params.generatedAt || new Date().toISOString()),
250
+ sourceBoundary,
251
+ budget,
252
+ fragments: selectedFragments,
253
+ sourceDecisions: decisions,
254
+ totalCharCount,
255
+ tokenEstimate,
256
+ };
257
+ }
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ragContextPack_1 = require("./ragContextPack");
4
+ function makeFragment(overrides = {}) {
5
+ const text = overrides.text || 'A water glass is a transparent drinking vessel that contains water.';
6
+ return {
7
+ fragmentId: overrides.fragmentId || `fragment_${overrides.role || 'direct_support'}`,
8
+ role: overrides.role || 'direct_support',
9
+ text,
10
+ atomId: overrides.atomId || 'atom_water_glass',
11
+ documentId: overrides.documentId || 'doc_water_glass',
12
+ sourcePath: overrides.sourcePath || 'Knowledge_Base/test/water-glass.md',
13
+ title: overrides.title || 'Water Glass',
14
+ headingPath: Array.isArray(overrides.headingPath) ? overrides.headingPath : ['Water Glass'],
15
+ startOffset: overrides.startOffset,
16
+ endOffset: overrides.endOffset,
17
+ startLine: overrides.startLine,
18
+ endLine: overrides.endLine,
19
+ charCount: text.length,
20
+ tokenEstimate: Math.ceil(text.length / 4),
21
+ truncated: overrides.truncated === true,
22
+ truncationReason: overrides.truncationReason,
23
+ citationIds: Array.isArray(overrides.citationIds) ? overrides.citationIds : ['evidence_water_glass'],
24
+ relationEdgeIds: Array.isArray(overrides.relationEdgeIds) ? overrides.relationEdgeIds : [],
25
+ score: Number.isFinite(overrides.score) ? Number(overrides.score) : 0.8,
26
+ sourceBoundary: overrides.sourceBoundary || 'direct_span_only',
27
+ };
28
+ }
29
+ describe('buildRagContextPack', () => {
30
+ test('generates a stable replay id from the selected evidence payload', () => {
31
+ const direct = makeFragment({
32
+ fragmentId: 'direct_water_glass',
33
+ role: 'direct_support',
34
+ text: 'Direct definition of water glass.',
35
+ score: 0.72,
36
+ });
37
+ const parent = makeFragment({
38
+ fragmentId: 'parent_water_glass',
39
+ role: 'parent_context',
40
+ text: 'Parent section explains the vessel boundary and optical qualifier.',
41
+ sourceBoundary: 'full_document',
42
+ score: 0.61,
43
+ });
44
+ const baseParams = {
45
+ query: 'what is water glass?',
46
+ sourceDecisions: [
47
+ {
48
+ documentId: 'doc_water_glass',
49
+ sourcePath: 'Knowledge_Base/test/water-glass.md',
50
+ sourceBoundary: 'full_document',
51
+ status: 'read',
52
+ charsRead: 4096,
53
+ },
54
+ ],
55
+ budget: {
56
+ maxFragments: 4,
57
+ maxCharsPerFragment: 400,
58
+ maxTotalChars: 900,
59
+ },
60
+ generatedAt: '2026-07-05T00:00:00.000Z',
61
+ };
62
+ const firstPack = (0, ragContextPack_1.buildRagContextPack)({
63
+ ...baseParams,
64
+ fragments: [parent, direct],
65
+ });
66
+ const secondPack = (0, ragContextPack_1.buildRagContextPack)({
67
+ ...baseParams,
68
+ fragments: [direct, parent],
69
+ });
70
+ const changedPack = (0, ragContextPack_1.buildRagContextPack)({
71
+ ...baseParams,
72
+ fragments: [
73
+ direct,
74
+ {
75
+ ...parent,
76
+ text: 'Parent section now carries a different qualifier.',
77
+ charCount: 'Parent section now carries a different qualifier.'.length,
78
+ },
79
+ ],
80
+ });
81
+ expect(firstPack.replayId).toMatch(/^ragctx_[a-f0-9]{16}$/);
82
+ expect(secondPack.replayId).toBe(firstPack.replayId);
83
+ expect(changedPack.replayId).not.toBe(firstPack.replayId);
84
+ });
85
+ test('middle-truncates oversized fragments while preserving the opening and terminal qualifier', () => {
86
+ const longText = [
87
+ 'Opening definition: a water glass is a transparent vessel.',
88
+ 'Middle detail '.repeat(30),
89
+ 'Terminal qualifier: this claim only covers the scoped note.',
90
+ ].join('\n');
91
+ const pack = (0, ragContextPack_1.buildRagContextPack)({
92
+ query: 'what is water glass?',
93
+ fragments: [
94
+ makeFragment({
95
+ role: 'parent_context',
96
+ text: longText,
97
+ sourceBoundary: 'full_document',
98
+ }),
99
+ ],
100
+ sourceDecisions: [],
101
+ budget: {
102
+ maxFragments: 3,
103
+ maxCharsPerFragment: 180,
104
+ maxTotalChars: 220,
105
+ },
106
+ generatedAt: '2026-07-05T00:00:00.000Z',
107
+ });
108
+ expect(pack.fragments).toHaveLength(1);
109
+ expect(pack.fragments[0].truncated).toBe(true);
110
+ expect(pack.fragments[0].text).toContain('Opening definition');
111
+ expect(pack.fragments[0].text).toContain('Terminal qualifier');
112
+ expect(pack.fragments[0].text).toContain('[...]');
113
+ expect(pack.sourceDecisions).toEqual(expect.arrayContaining([
114
+ expect.objectContaining({
115
+ status: 'fragment_truncated',
116
+ reason: 'max_chars_per_fragment_exceeded',
117
+ }),
118
+ ]));
119
+ });
120
+ test('uses role priority so weak background cannot displace direct or graph evidence', () => {
121
+ const pack = (0, ragContextPack_1.buildRagContextPack)({
122
+ query: 'what is water glass?',
123
+ fragments: [
124
+ makeFragment({
125
+ fragmentId: 'background_1',
126
+ role: 'background',
127
+ text: 'Background note with weak topical overlap.',
128
+ score: 0.95,
129
+ }),
130
+ makeFragment({
131
+ fragmentId: 'direct_1',
132
+ role: 'direct_support',
133
+ text: 'Direct definition of water glass.',
134
+ score: 0.7,
135
+ }),
136
+ makeFragment({
137
+ fragmentId: 'graph_1',
138
+ role: 'graph_neighbor_support',
139
+ text: 'Graph neighbor evidence about vessel boundary.',
140
+ score: 0.6,
141
+ sourceBoundary: 'full_document',
142
+ }),
143
+ ],
144
+ sourceDecisions: [],
145
+ budget: {
146
+ maxFragments: 2,
147
+ maxCharsPerFragment: 200,
148
+ maxTotalChars: 400,
149
+ },
150
+ });
151
+ expect(pack.fragments.map((fragment) => fragment.fragmentId)).toEqual(['direct_1', 'graph_1']);
152
+ expect(pack.sourceDecisions).toEqual(expect.arrayContaining([
153
+ expect.objectContaining({
154
+ status: 'fragment_dropped',
155
+ reason: 'max_fragments_exceeded',
156
+ documentId: 'doc_water_glass',
157
+ }),
158
+ ]));
159
+ });
160
+ });
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.naturalizeRagPublicEvidenceClause = naturalizeRagPublicEvidenceClause;
4
+ exports.shouldRejectCompareProcedureEvidenceClause = shouldRejectCompareProcedureEvidenceClause;
5
+ function normalizeWhitespace(value) {
6
+ return String(value || '').replace(/\s+/g, ' ').trim();
7
+ }
8
+ const LEADING_SOURCE_LABEL_PATTERN = /^(?:prerequisites?|preconditions?|requirements?|background|context|mechanism|reasoning boundary|downstream checks?|downstream consequences?|failure modes?|mitigation(?: neighbor)?|graph caveat|caveat|evidence|summary|note)\s*[:\uFF1A-]\s*/iu;
9
+ const PRESERVED_LEADING_LABEL_PATTERN = /^(?:step|phase|stage|section)\s*\d+\s*[:\uFF1A-]/iu;
10
+ function naturalizeRagPublicEvidenceClause(value) {
11
+ let normalized = normalizeWhitespace(value);
12
+ if (!normalized || PRESERVED_LEADING_LABEL_PATTERN.test(normalized)) {
13
+ return normalized;
14
+ }
15
+ for (let pass = 0; pass < 3; pass += 1) {
16
+ const next = normalizeWhitespace(normalized.replace(LEADING_SOURCE_LABEL_PATTERN, ''));
17
+ if (!next || next === normalized) {
18
+ break;
19
+ }
20
+ normalized = next;
21
+ if (PRESERVED_LEADING_LABEL_PATTERN.test(normalized)) {
22
+ break;
23
+ }
24
+ }
25
+ return normalized;
26
+ }
27
+ function shouldRejectCompareProcedureEvidenceClause(value, query) {
28
+ const normalizedClause = normalizeWhitespace(value).toLowerCase();
29
+ const normalizedQuery = normalizeWhitespace(query).toLowerCase();
30
+ if (!normalizedClause) {
31
+ return false;
32
+ }
33
+ if (/\b(?:procedure|procedural|workflow|runbook|steps?|step\s*\d+|sequence)\b/u.test(normalizedQuery)) {
34
+ return false;
35
+ }
36
+ return /\b(?:procedure|workflow|runbook|steps?|step\s*\d+)\b/u.test(normalizedClause)
37
+ || /\bprocedural\b.{0,80}\bsequence\b/u.test(normalizedClause);
38
+ }
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reviewRagContextSufficiency = reviewRagContextSufficiency;
4
+ function clampUnit(value) {
5
+ if (!Number.isFinite(value)) {
6
+ return 0;
7
+ }
8
+ return Number(Math.max(0, Math.min(1, value)).toFixed(4));
9
+ }
10
+ function hasCitation(fragment) {
11
+ return Array.isArray(fragment.citationIds) && fragment.citationIds.some((citationId) => String(citationId || '').trim());
12
+ }
13
+ function textHasSubstance(fragment) {
14
+ return String(fragment.text || '').trim().length >= 24;
15
+ }
16
+ function hasDirectSupport(fragments) {
17
+ return fragments.some((fragment) => fragment.role === 'direct_support' && hasCitation(fragment) && textHasSubstance(fragment));
18
+ }
19
+ function hasDocumentAugmentation(fragments) {
20
+ return fragments.some((fragment) => ((fragment.role === 'parent_context' || fragment.role === 'adjacent_context')
21
+ && fragment.sourceBoundary === 'full_document'
22
+ && textHasSubstance(fragment)));
23
+ }
24
+ function hasGraphEvidence(fragments) {
25
+ return fragments.some((fragment) => fragment.role === 'graph_neighbor_support' && hasCitation(fragment) && textHasSubstance(fragment));
26
+ }
27
+ function hasConflictEvidence(fragments) {
28
+ return fragments.some((fragment) => fragment.role === 'conflict' && textHasSubstance(fragment));
29
+ }
30
+ function hasUnavailableGraphNeighborSourceWindow(pack) {
31
+ return pack.sourceDecisions.some((decision) => (decision.status === 'source_window_unavailable'
32
+ && String(decision.reason || '').includes('graph_neighbor_support')));
33
+ }
34
+ function hasBudgetViolation(pack) {
35
+ return pack.sourceDecisions.some((decision) => (decision.status === 'fragment_dropped'
36
+ && (decision.reason === 'max_total_chars_exceeded' || decision.reason === 'max_fragments_exceeded')));
37
+ }
38
+ function buildDeterministicReview(params) {
39
+ const fragments = Array.isArray(params.contextPack.fragments) ? params.contextPack.fragments : [];
40
+ const directSupport = hasDirectSupport(fragments);
41
+ const documentAugmentation = hasDocumentAugmentation(fragments);
42
+ const graphEvidence = hasGraphEvidence(fragments);
43
+ const conflictEvidence = hasConflictEvidence(fragments);
44
+ const graphNeighborSourceUnavailable = hasUnavailableGraphNeighborSourceWindow(params.contextPack);
45
+ const budgetViolation = hasBudgetViolation(params.contextPack);
46
+ const reasons = [];
47
+ if (!directSupport) {
48
+ reasons.push('missing_direct_support');
49
+ }
50
+ if (!documentAugmentation) {
51
+ reasons.push('document_augmentation_missing');
52
+ }
53
+ const graphNeighborEvidenceMissing = Boolean(params.graphContext && (!graphEvidence || graphNeighborSourceUnavailable) && ((params.graphContext.predecessorWindow?.length || 0) > 0
54
+ || (params.graphContext.successorWindow?.length || 0) > 0));
55
+ if (graphNeighborEvidenceMissing) {
56
+ reasons.push('graph_neighbor_evidence_missing');
57
+ }
58
+ if (conflictEvidence) {
59
+ reasons.push('conflict_evidence_present');
60
+ }
61
+ if (budgetViolation) {
62
+ reasons.push('context_budget_dropped_fragments');
63
+ }
64
+ if (!directSupport) {
65
+ return {
66
+ reviewedAt: String(params.reviewedAt || new Date().toISOString()),
67
+ status: 'insufficient',
68
+ score: 0.2,
69
+ reasons,
70
+ deterministic: true,
71
+ recoveryAttempted: false,
72
+ llmJudgeUsed: false,
73
+ degradationState: 'insufficient_evidence',
74
+ };
75
+ }
76
+ let score = 0.58;
77
+ if (documentAugmentation) {
78
+ score += 0.24;
79
+ }
80
+ if (graphEvidence) {
81
+ score += 0.08;
82
+ }
83
+ if (!budgetViolation) {
84
+ score += 0.06;
85
+ }
86
+ if (conflictEvidence) {
87
+ score -= 0.18;
88
+ }
89
+ score = clampUnit(score);
90
+ const status = score >= 0.75
91
+ && documentAugmentation
92
+ && !conflictEvidence
93
+ && !graphNeighborEvidenceMissing
94
+ ? 'sufficient'
95
+ : 'borderline';
96
+ return {
97
+ reviewedAt: String(params.reviewedAt || new Date().toISOString()),
98
+ status,
99
+ score,
100
+ reasons,
101
+ deterministic: true,
102
+ recoveryAttempted: false,
103
+ llmJudgeUsed: false,
104
+ degradationState: status === 'sufficient'
105
+ ? 'none'
106
+ : conflictEvidence
107
+ ? 'conflict'
108
+ : 'partial_coverage',
109
+ };
110
+ }
111
+ function mergeLlmJudgeReview(deterministicReview, judgeReview) {
112
+ if (!judgeReview) {
113
+ return deterministicReview;
114
+ }
115
+ const nextStatus = judgeReview.status === 'sufficient'
116
+ || judgeReview.status === 'borderline'
117
+ || judgeReview.status === 'insufficient'
118
+ ? judgeReview.status
119
+ : deterministicReview.status;
120
+ const nextScore = Number.isFinite(judgeReview.score)
121
+ ? clampUnit(Number(judgeReview.score))
122
+ : deterministicReview.score;
123
+ const nextReasons = Array.isArray(judgeReview.reasons) && judgeReview.reasons.length > 0
124
+ ? judgeReview.reasons.map((reason) => String(reason || '').trim()).filter(Boolean)
125
+ : deterministicReview.reasons;
126
+ return {
127
+ ...deterministicReview,
128
+ ...judgeReview,
129
+ status: nextStatus,
130
+ score: nextScore,
131
+ reasons: nextReasons,
132
+ deterministic: false,
133
+ llmJudgeUsed: true,
134
+ };
135
+ }
136
+ async function reviewRagContextSufficiency(params) {
137
+ const deterministicReview = buildDeterministicReview(params);
138
+ if (deterministicReview.status !== 'borderline'
139
+ || params.allowLlmJudge !== true
140
+ || typeof params.llmJudge !== 'function') {
141
+ return deterministicReview;
142
+ }
143
+ try {
144
+ const judgeReview = await params.llmJudge({
145
+ query: params.query,
146
+ contextPack: params.contextPack,
147
+ graphContext: params.graphContext,
148
+ });
149
+ return mergeLlmJudgeReview(deterministicReview, judgeReview);
150
+ }
151
+ catch (error) {
152
+ return {
153
+ ...deterministicReview,
154
+ reasons: [
155
+ ...deterministicReview.reasons,
156
+ `llm_judge_failed:${String(error?.message || error || 'unknown')}`,
157
+ ],
158
+ llmJudgeUsed: false,
159
+ };
160
+ }
161
+ }