@gmickel/gno 1.16.0 → 1.18.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/README.md +34 -18
- package/assets/skill/SKILL.md +25 -6
- package/assets/skill/mcp-reference.md +21 -0
- package/package.json +2 -2
- package/src/app/context-agent-projection.ts +303 -0
- package/src/app/context-format.ts +249 -0
- package/src/app/context-runtime-contract.ts +325 -0
- package/src/app/context-runtime-input.ts +362 -0
- package/src/app/context-runtime-types.ts +65 -0
- package/src/app/context-runtime.ts +170 -0
- package/src/app/context-surface.ts +145 -0
- package/src/cli/commands/context-build.ts +149 -0
- package/src/cli/commands/context-verify.ts +90 -0
- package/src/cli/commands/daemon.ts +69 -2
- package/src/cli/commands/models/pull.ts +13 -3
- package/src/cli/commands/status.ts +2 -0
- package/src/cli/detach.ts +37 -20
- package/src/cli/options.ts +4 -0
- package/src/cli/program.ts +252 -27
- package/src/config/index.ts +3 -0
- package/src/config/types.ts +37 -0
- package/src/core/context-budget.ts +461 -0
- package/src/core/context-capsule-index-schema.ts +15 -0
- package/src/core/context-capsule-retrieval-schema.ts +81 -0
- package/src/core/context-capsule-schema.ts +473 -0
- package/src/core/context-capsule-validation.ts +416 -0
- package/src/core/context-capsule-verification.ts +218 -0
- package/src/core/context-capsule.ts +439 -0
- package/src/core/context-compiler.ts +513 -0
- package/src/core/context-evidence-metadata.ts +33 -0
- package/src/core/context-evidence.ts +495 -0
- package/src/core/context-facets.ts +163 -0
- package/src/core/context-guidance.ts +69 -0
- package/src/core/context-scope.ts +32 -0
- package/src/core/context-verifier-canonical.ts +90 -0
- package/src/core/context-verifier-input.ts +66 -0
- package/src/core/context-verifier.ts +447 -0
- package/src/core/job-manager.ts +19 -0
- package/src/core/mutation-generations.ts +33 -0
- package/src/core/sections.ts +63 -0
- package/src/llm/cache.ts +13 -3
- package/src/llm/nodeLlamaCpp/adapter.ts +10 -1
- package/src/llm/nodeLlamaCpp/lifecycle.ts +71 -0
- package/src/mcp/context.ts +161 -0
- package/src/mcp/http-security.ts +477 -0
- package/src/mcp/http-session.ts +272 -0
- package/src/mcp/http-transport.ts +370 -0
- package/src/mcp/resources/index.ts +141 -134
- package/src/mcp/server.ts +28 -82
- package/src/mcp/tools/add-collection.ts +3 -1
- package/src/mcp/tools/capture.ts +3 -0
- package/src/mcp/tools/clear-collection-embeddings.ts +2 -0
- package/src/mcp/tools/context.ts +230 -0
- package/src/mcp/tools/embed.ts +62 -52
- package/src/mcp/tools/index-cmd.ts +88 -74
- package/src/mcp/tools/index.ts +49 -2
- package/src/mcp/tools/remove-collection.ts +2 -0
- package/src/mcp/tools/status.ts +11 -0
- package/src/mcp/tools/sync.ts +16 -14
- package/src/mcp/tools/workspace-write.ts +7 -3
- package/src/pipeline/chunk-lookup.ts +33 -0
- package/src/pipeline/hybrid.ts +79 -57
- package/src/pipeline/types.ts +14 -0
- package/src/sdk/client.ts +68 -6
- package/src/sdk/index.ts +21 -0
- package/src/sdk/types.ts +24 -0
- package/src/serve/background-runtime.ts +12 -211
- package/src/serve/context-capsule.ts +136 -0
- package/src/serve/context.ts +10 -1
- package/src/serve/embed-scheduler.ts +74 -43
- package/src/serve/index.ts +9 -0
- package/src/serve/jobs.ts +78 -80
- package/src/serve/public/components/HealthCenter.tsx +74 -1
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Dashboard.tsx +1 -0
- package/src/serve/resident-admission.ts +159 -0
- package/src/serve/resident-background-work.ts +39 -0
- package/src/serve/resident-request.ts +55 -0
- package/src/serve/resident-runtime.ts +490 -0
- package/src/serve/resident-status.ts +96 -0
- package/src/serve/routes/api.ts +265 -167
- package/src/serve/routes/mcp.ts +69 -0
- package/src/serve/server.ts +212 -35
- package/src/serve/status-model.ts +51 -0
- package/src/serve/status.ts +5 -0
- package/src/store/sqlite/adapter.ts +64 -29
package/src/mcp/tools/status.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { IndexStatus } from "../../store/types";
|
|
|
8
8
|
import type { ToolContext } from "../server";
|
|
9
9
|
|
|
10
10
|
import { resolveModelUri } from "../../llm/registry";
|
|
11
|
+
import { createStandaloneResidentStatus } from "../../serve/resident-status";
|
|
11
12
|
import { runTool, type ToolResult } from "./index";
|
|
12
13
|
|
|
13
14
|
type StatusInput = Record<string, never>;
|
|
@@ -22,6 +23,14 @@ function formatStatus(status: IndexStatus): string {
|
|
|
22
23
|
lines.push(`Config: ${status.configPath}`);
|
|
23
24
|
lines.push(`Database: ${status.dbPath}`);
|
|
24
25
|
lines.push(`Health: ${status.healthy ? "OK" : "DEGRADED"}`);
|
|
26
|
+
if ("resident" in status) {
|
|
27
|
+
const resident = status.resident as NonNullable<
|
|
28
|
+
ReturnType<NonNullable<ToolContext["getResidentStatus"]>>
|
|
29
|
+
>;
|
|
30
|
+
lines.push(
|
|
31
|
+
`Runtime: ${resident.mode}${resident.resident ? ` (${resident.transport.activeSessions} sessions)` : " (standalone)"}`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
25
34
|
lines.push("");
|
|
26
35
|
|
|
27
36
|
if (status.collections.length === 0) {
|
|
@@ -78,6 +87,8 @@ export function handleStatus(
|
|
|
78
87
|
return {
|
|
79
88
|
...result.value,
|
|
80
89
|
configPath: ctx.actualConfigPath,
|
|
90
|
+
resident:
|
|
91
|
+
ctx.getResidentStatus?.() ?? createStandaloneResidentStatus("stdio"),
|
|
81
92
|
};
|
|
82
93
|
},
|
|
83
94
|
formatStatus
|
package/src/mcp/tools/sync.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { ToolContext } from "../server";
|
|
|
11
11
|
import { MCP_ERRORS } from "../../core/errors";
|
|
12
12
|
import { acquireWriteLock, type WriteLockHandle } from "../../core/file-lock";
|
|
13
13
|
import { JobError } from "../../core/job-manager";
|
|
14
|
+
import { recordContentMutation } from "../../core/mutation-generations";
|
|
14
15
|
import { normalizeCollectionName } from "../../core/validation";
|
|
15
16
|
import { defaultSyncService, withContentTypeRules } from "../../ingestion";
|
|
16
17
|
import { runTool, type ToolResult } from "./index";
|
|
@@ -113,20 +114,21 @@ export function handleSync(
|
|
|
113
114
|
"sync",
|
|
114
115
|
lock,
|
|
115
116
|
async () => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
);
|
|
117
|
+
const result = collection
|
|
118
|
+
? wrapSingleSync(
|
|
119
|
+
await defaultSyncService.syncCollection(
|
|
120
|
+
collection,
|
|
121
|
+
ctx.store,
|
|
122
|
+
options
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
: await defaultSyncService.syncAll(
|
|
126
|
+
ctx.collections,
|
|
127
|
+
ctx.store,
|
|
128
|
+
options
|
|
129
|
+
);
|
|
130
|
+
recordContentMutation(result, ctx.markContentMutation);
|
|
131
|
+
return result;
|
|
130
132
|
}
|
|
131
133
|
);
|
|
132
134
|
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
planMoveRefactor,
|
|
28
28
|
planRenameRefactor,
|
|
29
29
|
} from "../../core/file-refactors";
|
|
30
|
+
import { recordContentMutation } from "../../core/mutation-generations";
|
|
30
31
|
import { defaultSyncService, withContentTypeRules } from "../../ingestion";
|
|
31
32
|
import { runTool, type ToolResult } from "./index";
|
|
32
33
|
|
|
@@ -210,11 +211,12 @@ export function handleRenameNote(
|
|
|
210
211
|
const currentPath = join(collection.path, doc.relPath);
|
|
211
212
|
const nextPath = join(collection.path, plan.nextRelPath);
|
|
212
213
|
await renameFilePath(currentPath, nextPath);
|
|
213
|
-
await defaultSyncService.syncCollection(
|
|
214
|
+
const syncResult = await defaultSyncService.syncCollection(
|
|
214
215
|
collection,
|
|
215
216
|
ctx.store,
|
|
216
217
|
withContentTypeRules({ runUpdateCmd: false }, ctx.config)
|
|
217
218
|
);
|
|
219
|
+
recordContentMutation(syncResult, ctx.markContentMutation);
|
|
218
220
|
return {
|
|
219
221
|
uri: plan.nextUri,
|
|
220
222
|
relPath: plan.nextRelPath,
|
|
@@ -255,11 +257,12 @@ export function handleMoveNote(
|
|
|
255
257
|
const nextPath = join(collection.path, plan.nextRelPath);
|
|
256
258
|
await mkdir(dirname(nextPath), { recursive: true });
|
|
257
259
|
await renameFilePath(currentPath, nextPath);
|
|
258
|
-
await defaultSyncService.syncCollection(
|
|
260
|
+
const syncResult = await defaultSyncService.syncCollection(
|
|
259
261
|
collection,
|
|
260
262
|
ctx.store,
|
|
261
263
|
withContentTypeRules({ runUpdateCmd: false }, ctx.config)
|
|
262
264
|
);
|
|
265
|
+
recordContentMutation(syncResult, ctx.markContentMutation);
|
|
263
266
|
return {
|
|
264
267
|
uri: plan.nextUri,
|
|
265
268
|
relPath: plan.nextRelPath,
|
|
@@ -308,11 +311,12 @@ export function handleDuplicateNote(
|
|
|
308
311
|
const nextPath = join(collection.path, plan.nextRelPath);
|
|
309
312
|
await mkdir(dirname(nextPath), { recursive: true });
|
|
310
313
|
await copyFilePath(currentPath, nextPath);
|
|
311
|
-
await defaultSyncService.syncCollection(
|
|
314
|
+
const syncResult = await defaultSyncService.syncCollection(
|
|
312
315
|
collection,
|
|
313
316
|
ctx.store,
|
|
314
317
|
withContentTypeRules({ runUpdateCmd: false }, ctx.config)
|
|
315
318
|
);
|
|
319
|
+
recordContentMutation(syncResult, ctx.markContentMutation);
|
|
316
320
|
return {
|
|
317
321
|
uri: plan.nextUri,
|
|
318
322
|
relPath: plan.nextRelPath,
|
|
@@ -42,3 +42,36 @@ export function createChunkLookup(
|
|
|
42
42
|
return bySeq.get(seq);
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Prove that persisted chunk coordinates still address the exact stored
|
|
48
|
+
* canonical mirror bytes. Chunk text may begin or end mid-line; callers that
|
|
49
|
+
* need citation spans must expand it to full lines separately.
|
|
50
|
+
*/
|
|
51
|
+
export function chunkMatchesCanonicalContent(
|
|
52
|
+
chunk: ChunkRow,
|
|
53
|
+
content: string
|
|
54
|
+
): boolean {
|
|
55
|
+
if (
|
|
56
|
+
content.includes("\r") ||
|
|
57
|
+
chunk.pos < 0 ||
|
|
58
|
+
chunk.startLine < 1 ||
|
|
59
|
+
chunk.endLine < chunk.startLine ||
|
|
60
|
+
chunk.text.length === 0 ||
|
|
61
|
+
chunk.pos + chunk.text.length > content.length
|
|
62
|
+
) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
if (content.slice(chunk.pos, chunk.pos + chunk.text.length) !== chunk.text) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
let startLine = 1;
|
|
69
|
+
let endLine = 1;
|
|
70
|
+
const endOffset = chunk.pos + chunk.text.length - 1;
|
|
71
|
+
for (let offset = 0; offset < endOffset; offset += 1) {
|
|
72
|
+
if (content[offset] !== "\n") continue;
|
|
73
|
+
if (offset < chunk.pos) startLine += 1;
|
|
74
|
+
endLine += 1;
|
|
75
|
+
}
|
|
76
|
+
return startLine === chunk.startLine && endLine === chunk.endLine;
|
|
77
|
+
}
|
package/src/pipeline/hybrid.ts
CHANGED
|
@@ -54,7 +54,10 @@ import {
|
|
|
54
54
|
resolveTemporalRange,
|
|
55
55
|
shouldSortByRecency,
|
|
56
56
|
} from "./temporal";
|
|
57
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
DEFAULT_PIPELINE_CONFIG,
|
|
59
|
+
SEARCH_RESULT_PLANNER_METADATA,
|
|
60
|
+
} from "./types";
|
|
58
61
|
|
|
59
62
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
60
63
|
// Dependencies
|
|
@@ -719,7 +722,16 @@ export async function searchHybrid(
|
|
|
719
722
|
}
|
|
720
723
|
|
|
721
724
|
// Build lookup maps.
|
|
722
|
-
const
|
|
725
|
+
const docsByMirrorHash = new Map<
|
|
726
|
+
string,
|
|
727
|
+
(typeof docsResult.value)[number][]
|
|
728
|
+
>();
|
|
729
|
+
const addDocument = (doc: (typeof docsResult.value)[number]): void => {
|
|
730
|
+
if (!doc.mirrorHash) return;
|
|
731
|
+
const docs = docsByMirrorHash.get(doc.mirrorHash) ?? [];
|
|
732
|
+
docs.push(doc);
|
|
733
|
+
docsByMirrorHash.set(doc.mirrorHash, docs);
|
|
734
|
+
};
|
|
723
735
|
const matchesMetadataFilters = (
|
|
724
736
|
doc: (typeof docsResult.value)[number]
|
|
725
737
|
): boolean => {
|
|
@@ -761,7 +773,7 @@ export async function searchHybrid(
|
|
|
761
773
|
candidateDocs.push(doc);
|
|
762
774
|
} else {
|
|
763
775
|
if (matchesMetadataFilters(doc)) {
|
|
764
|
-
|
|
776
|
+
addDocument(doc);
|
|
765
777
|
}
|
|
766
778
|
}
|
|
767
779
|
}
|
|
@@ -789,12 +801,20 @@ export async function searchHybrid(
|
|
|
789
801
|
}
|
|
790
802
|
|
|
791
803
|
if (doc.mirrorHash && matchesMetadataFilters(doc)) {
|
|
792
|
-
|
|
804
|
+
addDocument(doc);
|
|
793
805
|
}
|
|
794
806
|
}
|
|
795
807
|
}
|
|
796
808
|
}
|
|
797
809
|
|
|
810
|
+
for (const docs of docsByMirrorHash.values()) {
|
|
811
|
+
docs.sort((left, right) => {
|
|
812
|
+
if (left.uri < right.uri) return -1;
|
|
813
|
+
if (left.uri > right.uri) return 1;
|
|
814
|
+
return left.docid < right.docid ? -1 : left.docid > right.docid ? 1 : 0;
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
|
|
798
818
|
const collectionPaths = new Map<string, string>();
|
|
799
819
|
if (collectionsResult.ok) {
|
|
800
820
|
for (const c of collectionsResult.value) {
|
|
@@ -823,34 +843,19 @@ export async function searchHybrid(
|
|
|
823
843
|
const seenDocids = new Set<string>();
|
|
824
844
|
|
|
825
845
|
// Iterate until we have enough results (don't slice early - deduping may skip candidates)
|
|
826
|
-
for (const candidate of filteredCandidates) {
|
|
846
|
+
for (const [candidateIndex, candidate] of filteredCandidates.entries()) {
|
|
827
847
|
// Stop when we have enough results
|
|
828
848
|
if (results.length >= assemblyLimit) {
|
|
829
849
|
break;
|
|
830
850
|
}
|
|
831
851
|
|
|
832
852
|
// Find document from pre-fetched map
|
|
833
|
-
const
|
|
834
|
-
if (
|
|
853
|
+
const candidateDocs = docsByMirrorHash.get(candidate.mirrorHash) ?? [];
|
|
854
|
+
if (candidateDocs.length === 0) {
|
|
835
855
|
continue;
|
|
836
856
|
}
|
|
837
857
|
|
|
838
858
|
const docChunks = chunksMap.get(candidate.mirrorHash) ?? [];
|
|
839
|
-
const filterEval = evaluateDocumentChunkFilters(
|
|
840
|
-
query,
|
|
841
|
-
doc,
|
|
842
|
-
docChunks,
|
|
843
|
-
options
|
|
844
|
-
);
|
|
845
|
-
if (!filterEval.matches) {
|
|
846
|
-
continue;
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
// For --full mode, de-dupe by docid (keep best scoring candidate per doc)
|
|
850
|
-
if (options.full && seenDocids.has(doc.docid)) {
|
|
851
|
-
continue;
|
|
852
|
-
}
|
|
853
|
-
|
|
854
859
|
// Get chunk via O(1) lookup
|
|
855
860
|
// For doc-level FTS (seq=0), fall back to first available chunk if exact lookup fails
|
|
856
861
|
let chunk = getChunk(candidate.mirrorHash, candidate.seq);
|
|
@@ -868,10 +873,6 @@ export async function searchHybrid(
|
|
|
868
873
|
continue;
|
|
869
874
|
}
|
|
870
875
|
|
|
871
|
-
docidMap.set(`${candidate.mirrorHash}:${candidate.seq}`, doc.docid);
|
|
872
|
-
|
|
873
|
-
const collectionPath = collectionPaths.get(doc.collection);
|
|
874
|
-
|
|
875
876
|
// For --full mode, fetch full mirror content
|
|
876
877
|
const snippetChunk =
|
|
877
878
|
options.full || !options.intent?.trim()
|
|
@@ -907,37 +908,58 @@ export async function searchHybrid(
|
|
|
907
908
|
// Fallback to chunk text if content unavailable
|
|
908
909
|
}
|
|
909
910
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
911
|
+
for (const doc of candidateDocs) {
|
|
912
|
+
if (results.length >= assemblyLimit) break;
|
|
913
|
+
const filterEval = evaluateDocumentChunkFilters(
|
|
914
|
+
query,
|
|
915
|
+
doc,
|
|
916
|
+
docChunks,
|
|
917
|
+
options
|
|
918
|
+
);
|
|
919
|
+
if (!filterEval.matches || (options.full && seenDocids.has(doc.docid))) {
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
const docidKey = `${candidate.mirrorHash}:${candidate.seq}`;
|
|
923
|
+
if (!docidMap.has(docidKey)) docidMap.set(docidKey, doc.docid);
|
|
924
|
+
const collectionPath = collectionPaths.get(doc.collection);
|
|
925
|
+
seenDocids.add(doc.docid);
|
|
926
|
+
results.push({
|
|
927
|
+
docid: doc.docid,
|
|
928
|
+
score: candidate.blendedScore,
|
|
929
|
+
uri: doc.uri,
|
|
930
|
+
title: doc.title ?? undefined,
|
|
931
|
+
contentType: doc.contentType ?? undefined,
|
|
932
|
+
categories: doc.categories ?? undefined,
|
|
933
|
+
line: snippetChunk.startLine,
|
|
934
|
+
snippet,
|
|
935
|
+
snippetLanguage: chunk.language ?? undefined,
|
|
936
|
+
snippetRange,
|
|
937
|
+
source: {
|
|
938
|
+
relPath: doc.relPath,
|
|
939
|
+
absPath: collectionPath
|
|
940
|
+
? `${collectionPath}/${doc.relPath}`
|
|
941
|
+
: undefined,
|
|
942
|
+
mime: doc.sourceMime,
|
|
943
|
+
ext: doc.sourceExt,
|
|
944
|
+
modifiedAt: doc.sourceMtime,
|
|
945
|
+
documentDate: doc.frontmatterDate ?? undefined,
|
|
946
|
+
sizeBytes: doc.sourceSize,
|
|
947
|
+
sourceHash: doc.sourceHash,
|
|
948
|
+
},
|
|
949
|
+
conversion: {
|
|
950
|
+
mirrorHash: candidate.mirrorHash,
|
|
951
|
+
converterId: doc.converterId ?? undefined,
|
|
952
|
+
converterVersion: doc.converterVersion ?? undefined,
|
|
953
|
+
},
|
|
954
|
+
[SEARCH_RESULT_PLANNER_METADATA]: {
|
|
955
|
+
retrievalRank: candidateIndex + 1,
|
|
956
|
+
mirrorHash: candidate.mirrorHash,
|
|
957
|
+
seq: snippetChunk.seq,
|
|
958
|
+
sources: [...candidate.sources].sort(),
|
|
959
|
+
graphExpanded: candidate.sources.includes("graph"),
|
|
960
|
+
},
|
|
961
|
+
});
|
|
962
|
+
}
|
|
941
963
|
}
|
|
942
964
|
timings.assemblyMs = performance.now() - assemblyStartedAt;
|
|
943
965
|
timings.totalMs = performance.now() - runStartedAt;
|
package/src/pipeline/types.ts
CHANGED
|
@@ -37,6 +37,19 @@ export interface SnippetRange {
|
|
|
37
37
|
endLine: number;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/** Symbol-keyed planner metadata; omitted from JSON/API projections. */
|
|
41
|
+
export const SEARCH_RESULT_PLANNER_METADATA = Symbol(
|
|
42
|
+
"gno.searchResultPlannerMetadata"
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
export interface SearchResultPlannerMetadata {
|
|
46
|
+
retrievalRank: number;
|
|
47
|
+
mirrorHash: string;
|
|
48
|
+
seq: number;
|
|
49
|
+
sources: FusionSource[];
|
|
50
|
+
graphExpanded: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
40
53
|
/** Single search result matching output schema */
|
|
41
54
|
export interface SearchResult {
|
|
42
55
|
docid: string;
|
|
@@ -53,6 +66,7 @@ export interface SearchResult {
|
|
|
53
66
|
context?: string;
|
|
54
67
|
source: SearchResultSource;
|
|
55
68
|
conversion?: SearchResultConversion;
|
|
69
|
+
[SEARCH_RESULT_PLANNER_METADATA]?: SearchResultPlannerMetadata;
|
|
56
70
|
}
|
|
57
71
|
|
|
58
72
|
/** Search mode enum */
|
package/src/sdk/client.ts
CHANGED
|
@@ -22,6 +22,9 @@ import type {
|
|
|
22
22
|
GnoCreateFolderResult,
|
|
23
23
|
GnoCreateNoteOptions,
|
|
24
24
|
GnoCreateNoteResult,
|
|
25
|
+
GnoContextInput,
|
|
26
|
+
GnoContextResult,
|
|
27
|
+
GnoContextVerificationResult,
|
|
25
28
|
GnoClientInitOptions,
|
|
26
29
|
GnoDuplicateNoteOptions,
|
|
27
30
|
GnoEmbedOptions,
|
|
@@ -39,8 +42,21 @@ import type {
|
|
|
39
42
|
GnoVectorSearchOptions,
|
|
40
43
|
} from "./types";
|
|
41
44
|
|
|
42
|
-
import {
|
|
43
|
-
|
|
45
|
+
import {
|
|
46
|
+
decorateUriForIndex,
|
|
47
|
+
DEFAULT_INDEX_NAME,
|
|
48
|
+
getIndexDbPath,
|
|
49
|
+
} from "../app/constants";
|
|
50
|
+
import {
|
|
51
|
+
buildContextCapsule,
|
|
52
|
+
validateContextCapsuleBuildInput,
|
|
53
|
+
verifyContextCapsuleRuntime,
|
|
54
|
+
} from "../app/context-runtime";
|
|
55
|
+
import {
|
|
56
|
+
canonicalizeIndexName,
|
|
57
|
+
INDEX_NAME_REQUIREMENTS,
|
|
58
|
+
isValidIndexName,
|
|
59
|
+
} from "../app/index-name";
|
|
44
60
|
import {
|
|
45
61
|
ConfigSchema,
|
|
46
62
|
loadConfig,
|
|
@@ -108,7 +124,7 @@ interface OpenedClientState {
|
|
|
108
124
|
store: SqliteAdapter;
|
|
109
125
|
llm: LlmAdapter;
|
|
110
126
|
downloadPolicy: DownloadPolicy;
|
|
111
|
-
indexName
|
|
127
|
+
indexName: string;
|
|
112
128
|
}
|
|
113
129
|
|
|
114
130
|
interface RuntimePorts {
|
|
@@ -161,7 +177,10 @@ async function resolveClientState(
|
|
|
161
177
|
configSource = "file";
|
|
162
178
|
}
|
|
163
179
|
|
|
164
|
-
const
|
|
180
|
+
const indexName = canonicalizeIndexName(
|
|
181
|
+
options.indexName ?? DEFAULT_INDEX_NAME
|
|
182
|
+
);
|
|
183
|
+
const dbPath = options.dbPath ?? getIndexDbPath(indexName);
|
|
165
184
|
await mkdir(dirname(dbPath), { recursive: true });
|
|
166
185
|
|
|
167
186
|
const store = new SqliteAdapter();
|
|
@@ -179,7 +198,7 @@ async function resolveClientState(
|
|
|
179
198
|
llm: new LlmAdapter(config, options.cacheDir),
|
|
180
199
|
downloadPolicy:
|
|
181
200
|
options.downloadPolicy ?? resolveDownloadPolicy(process.env, {}),
|
|
182
|
-
indexName
|
|
201
|
+
indexName,
|
|
183
202
|
};
|
|
184
203
|
}
|
|
185
204
|
|
|
@@ -192,7 +211,7 @@ class GnoClientImpl implements GnoClient {
|
|
|
192
211
|
private readonly store: SqliteAdapter;
|
|
193
212
|
private readonly llm: LlmAdapter;
|
|
194
213
|
private readonly downloadPolicy: DownloadPolicy;
|
|
195
|
-
private readonly indexName
|
|
214
|
+
private readonly indexName: string;
|
|
196
215
|
private closed = false;
|
|
197
216
|
|
|
198
217
|
constructor(state: OpenedClientState) {
|
|
@@ -644,6 +663,49 @@ class GnoClientImpl implements GnoClient {
|
|
|
644
663
|
}
|
|
645
664
|
}
|
|
646
665
|
|
|
666
|
+
async context(input: GnoContextInput): Promise<GnoContextResult> {
|
|
667
|
+
this.assertOpen();
|
|
668
|
+
validateContextCapsuleBuildInput(
|
|
669
|
+
{ ...input, indexName: this.indexName },
|
|
670
|
+
this.indexName,
|
|
671
|
+
this.config.collections.map((collection) => collection.name)
|
|
672
|
+
);
|
|
673
|
+
const collection =
|
|
674
|
+
input.collections?.length === 1 ? input.collections[0] : undefined;
|
|
675
|
+
const useModels = input.depthPolicy !== "fast";
|
|
676
|
+
const ports = await this.createRuntimePorts({
|
|
677
|
+
embed: useModels,
|
|
678
|
+
rerank: useModels,
|
|
679
|
+
collection,
|
|
680
|
+
});
|
|
681
|
+
try {
|
|
682
|
+
return await buildContextCapsule(
|
|
683
|
+
{ ...input, indexName: this.indexName },
|
|
684
|
+
{
|
|
685
|
+
store: this.store,
|
|
686
|
+
config: this.config,
|
|
687
|
+
indexName: this.indexName,
|
|
688
|
+
vectorIndex: ports.vectorIndex,
|
|
689
|
+
embedPort: ports.embedPort,
|
|
690
|
+
rerankPort: ports.rerankPort,
|
|
691
|
+
}
|
|
692
|
+
);
|
|
693
|
+
} finally {
|
|
694
|
+
await this.disposeRuntimePorts(ports);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
async verifyContext(
|
|
699
|
+
capsule: GnoContextResult
|
|
700
|
+
): Promise<GnoContextVerificationResult> {
|
|
701
|
+
this.assertOpen();
|
|
702
|
+
return verifyContextCapsuleRuntime(capsule, {
|
|
703
|
+
store: this.store,
|
|
704
|
+
config: this.config,
|
|
705
|
+
indexName: this.indexName,
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
|
|
647
709
|
async get(ref: string, options: GnoGetOptions = {}) {
|
|
648
710
|
this.assertOpen();
|
|
649
711
|
const resolution = resolveEffectiveIndex([ref], this.indexName);
|
package/src/sdk/index.ts
CHANGED
|
@@ -31,6 +31,10 @@ export type {
|
|
|
31
31
|
GnoAskOptions,
|
|
32
32
|
GnoCaptureOptions,
|
|
33
33
|
GnoCaptureResult,
|
|
34
|
+
GnoContextErrorCode,
|
|
35
|
+
GnoContextInput,
|
|
36
|
+
GnoContextResult,
|
|
37
|
+
GnoContextVerificationResult,
|
|
34
38
|
GnoClient,
|
|
35
39
|
GnoClientInitOptions,
|
|
36
40
|
GnoEmbedOptions,
|
|
@@ -51,3 +55,20 @@ export type {
|
|
|
51
55
|
GnoUpdateOptions,
|
|
52
56
|
GnoVectorSearchOptions,
|
|
53
57
|
} from "./types";
|
|
58
|
+
export {
|
|
59
|
+
ContextCapsuleContractError,
|
|
60
|
+
type ContextCapsuleErrorCode,
|
|
61
|
+
type ContextCapsuleV1,
|
|
62
|
+
} from "../core/context-capsule";
|
|
63
|
+
export {
|
|
64
|
+
ContextEvidenceError,
|
|
65
|
+
type ContextEvidenceErrorCode,
|
|
66
|
+
} from "../core/context-evidence";
|
|
67
|
+
export {
|
|
68
|
+
ContextVerifierError,
|
|
69
|
+
type ContextVerifierErrorCode,
|
|
70
|
+
} from "../core/context-verifier";
|
|
71
|
+
export {
|
|
72
|
+
ContextRuntimeError,
|
|
73
|
+
type ContextRuntimeErrorCode,
|
|
74
|
+
} from "../app/context-runtime";
|
package/src/sdk/types.ts
CHANGED
|
@@ -4,8 +4,19 @@
|
|
|
4
4
|
* @module src/sdk/types
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import type {
|
|
8
|
+
ContextCapsuleBuildInput,
|
|
9
|
+
ContextRuntimeErrorCode,
|
|
10
|
+
} from "../app/context-runtime";
|
|
7
11
|
import type { Config } from "../config/types";
|
|
8
12
|
import type { CaptureInput, CaptureReceipt } from "../core/capture";
|
|
13
|
+
import type {
|
|
14
|
+
ContextCapsuleErrorCode,
|
|
15
|
+
ContextCapsuleV1,
|
|
16
|
+
ContextCapsuleVerification,
|
|
17
|
+
} from "../core/context-capsule";
|
|
18
|
+
import type { ContextEvidenceErrorCode } from "../core/context-evidence";
|
|
19
|
+
import type { ContextVerifierErrorCode } from "../core/context-verifier";
|
|
9
20
|
import type { NoteCollisionPolicy } from "../core/note-creation";
|
|
10
21
|
import type { NotePresetId } from "../core/note-presets";
|
|
11
22
|
import type { DocumentSection } from "../core/sections";
|
|
@@ -65,6 +76,15 @@ export type GnoVectorSearchOptions = SearchOptions & {
|
|
|
65
76
|
model?: string;
|
|
66
77
|
};
|
|
67
78
|
|
|
79
|
+
export type GnoContextInput = Omit<ContextCapsuleBuildInput, "indexName">;
|
|
80
|
+
export type GnoContextResult = ContextCapsuleV1;
|
|
81
|
+
export type GnoContextVerificationResult = ContextCapsuleVerification;
|
|
82
|
+
export type GnoContextErrorCode =
|
|
83
|
+
| ContextRuntimeErrorCode
|
|
84
|
+
| ContextCapsuleErrorCode
|
|
85
|
+
| ContextEvidenceErrorCode
|
|
86
|
+
| ContextVerifierErrorCode;
|
|
87
|
+
|
|
68
88
|
export interface GnoGetOptions {
|
|
69
89
|
from?: number;
|
|
70
90
|
limit?: number;
|
|
@@ -185,6 +205,10 @@ export interface GnoClient {
|
|
|
185
205
|
): Promise<SearchResults>;
|
|
186
206
|
query(query: string, options?: GnoQueryOptions): Promise<SearchResults>;
|
|
187
207
|
ask(query: string, options?: GnoAskOptions): Promise<AskResult>;
|
|
208
|
+
context(input: GnoContextInput): Promise<GnoContextResult>;
|
|
209
|
+
verifyContext(
|
|
210
|
+
capsule: ContextCapsuleV1
|
|
211
|
+
): Promise<GnoContextVerificationResult>;
|
|
188
212
|
get(
|
|
189
213
|
ref: string,
|
|
190
214
|
options?: GnoGetOptions
|