@gmickel/gno 2.10.1 → 2.11.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 +11 -11
- package/assets/skill/SKILL.md +25 -14
- package/assets/skill/cli-reference.md +6 -5
- package/assets/skill/examples.md +16 -12
- package/assets/skill/mcp-reference.md +2 -1
- package/browser-extension/artifacts/{gno-browser-clipper-v2.10.1.zip → gno-browser-clipper-v2.11.0.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.11.0.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +3 -1
- package/spec/cli.md +27 -1
- package/spec/mcp.md +27 -3
- package/spec/output-schemas/ask.schema.json +8 -0
- package/spec/output-schemas/claim-verification.schema.json +8 -2
- package/spec/output-schemas/context-capsule-v1.schema.json +6 -1
- package/spec/output-schemas/context-capsule-verification.schema.json +4 -2
- package/spec/output-schemas/get.schema.json +4 -0
- package/spec/output-schemas/metadata-summary.schema.json +60 -0
- package/spec/output-schemas/multi-get.schema.json +4 -0
- package/spec/output-schemas/search-result.schema.json +4 -0
- package/spec/output-schemas/search-results.schema.json +4 -0
- package/src/app/constants.ts +16 -0
- package/src/app/context-format.ts +1 -0
- package/src/app/verified-ask.ts +2 -0
- package/src/cli/commands/agents/block.ts +9 -8
- package/src/cli/commands/ask-format.ts +18 -1
- package/src/cli/commands/ask.ts +4 -5
- package/src/cli/commands/daemon.ts +5 -1
- package/src/cli/commands/get.ts +11 -1
- package/src/cli/commands/metadata.ts +79 -0
- package/src/cli/commands/multi-get.ts +13 -0
- package/src/cli/commands/shared.ts +9 -7
- package/src/cli/format/search-results.ts +11 -0
- package/src/cli/options.ts +2 -0
- package/src/cli/program.ts +45 -0
- package/src/core/context-capsule-schema.ts +2 -0
- package/src/core/context-capsule-verification.ts +2 -0
- package/src/core/context-compiler.ts +2 -5
- package/src/core/context-evidence.ts +1 -0
- package/src/core/context-verifier.ts +14 -1
- package/src/core/metadata-discovery.ts +169 -0
- package/src/ingestion/sync.ts +49 -1
- package/src/ingestion/walker.ts +11 -3
- package/src/mcp/http-egress.ts +1 -0
- package/src/mcp/tool-descriptions-core.ts +2 -2
- package/src/mcp/tool-profile.ts +16 -1
- package/src/mcp/tools/get.ts +10 -0
- package/src/mcp/tools/index.ts +39 -4
- package/src/mcp/tools/multi-get.ts +15 -0
- package/src/mcp/tools/query.ts +5 -3
- package/src/mcp/tools/search.ts +5 -3
- package/src/mcp/tools/vsearch.ts +5 -3
- package/src/mcp/tools/workspace-write.ts +42 -34
- package/src/pipeline/answer-prompt.ts +15 -2
- package/src/pipeline/answer.ts +3 -0
- package/src/pipeline/claim-verification-schema.ts +6 -1
- package/src/pipeline/claim-verification.ts +54 -1
- package/src/pipeline/explain.ts +1 -1
- package/src/pipeline/fusion.ts +24 -4
- package/src/pipeline/hybrid.ts +5 -1
- package/src/pipeline/result-context.ts +29 -0
- package/src/pipeline/search.ts +5 -1
- package/src/pipeline/types.ts +4 -0
- package/src/pipeline/vsearch.ts +5 -1
- package/src/sdk/client.ts +32 -4
- package/src/sdk/documents.ts +5 -0
- package/src/sdk/types.ts +5 -0
- package/src/serve/routes/api.ts +29 -1
- package/src/serve/server.ts +12 -0
- package/src/store/sqlite/adapter.ts +82 -2
- package/src/store/types.ts +16 -0
- package/src/store/vector/variant-search.ts +112 -74
- package/browser-extension/artifacts/gno-browser-clipper-v2.10.1.zip.sha256 +0 -1
|
@@ -82,6 +82,32 @@ export function vectorSearchUnavailableMessage(
|
|
|
82
82
|
}`;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
const MAX_CACHED_PROOFS = 100_000;
|
|
86
|
+
const proofCaches = new WeakMap<
|
|
87
|
+
Database,
|
|
88
|
+
{ marker: string; proofs: Map<string, boolean> }
|
|
89
|
+
>();
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Input-hash proofs cached per connection. Any committed write, from this
|
|
93
|
+
* connection or another, changes the marker and drops the cache, so a cached
|
|
94
|
+
* proof never outlives the titles and chunk text it was computed from.
|
|
95
|
+
*/
|
|
96
|
+
function provenOwners(db: Database): Map<string, boolean> {
|
|
97
|
+
const { version, changes } = db
|
|
98
|
+
.query<{ version: number; changes: number }, []>(
|
|
99
|
+
"SELECT (SELECT data_version FROM pragma_data_version) AS version, total_changes() AS changes"
|
|
100
|
+
)
|
|
101
|
+
.get()!;
|
|
102
|
+
const marker = `${version}:${changes}`;
|
|
103
|
+
let cache = proofCaches.get(db);
|
|
104
|
+
if (cache?.marker !== marker || cache.proofs.size > MAX_CACHED_PROOFS) {
|
|
105
|
+
cache = { marker, proofs: new Map() };
|
|
106
|
+
proofCaches.set(db, cache);
|
|
107
|
+
}
|
|
108
|
+
return cache.proofs;
|
|
109
|
+
}
|
|
110
|
+
|
|
85
111
|
/** Null means legacy authority. Once promoted, unavailable provenance fails closed. */
|
|
86
112
|
function searchVectorVariantsInSnapshot(
|
|
87
113
|
db: Database,
|
|
@@ -148,14 +174,9 @@ function searchVectorVariantsInSnapshot(
|
|
|
148
174
|
const tableName = `vec_v1_${partitionId}`;
|
|
149
175
|
if (!db.query("SELECT 1 FROM sqlite_master WHERE name = ?").get(tableName))
|
|
150
176
|
throw new Error("Activated variant index unavailable; run gno embed");
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
`SELECT 1 FROM vector_variants v LEFT JOIN ${tableName} x ON x.variant_id = v.variant_id WHERE v.partition_id = ? AND (x.variant_id IS NULL OR x.embedding != v.embedding) LIMIT 1`
|
|
155
|
-
)
|
|
156
|
-
.get(partitionId)
|
|
157
|
-
)
|
|
158
|
-
throw new Error("Activated variant index inconsistent; run gno embed");
|
|
177
|
+
// The vec0 mirror is written in the same transactions as vector_variants and
|
|
178
|
+
// checked at activation and by `gno vec sync`; ranking below reads only
|
|
179
|
+
// vector_variants, so the mirror is never trusted here.
|
|
159
180
|
const eligible = buildEligibleDocumentQuery(
|
|
160
181
|
{ ...options.eligibility, semanticMetadata: true },
|
|
161
182
|
db
|
|
@@ -170,75 +191,92 @@ function searchVectorVariantsInSnapshot(
|
|
|
170
191
|
conditions.push("o.mirror_hash IN (SELECT value FROM json_each(?))");
|
|
171
192
|
params.push(JSON.stringify(options.allowedMirrorHashes));
|
|
172
193
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
JOIN documents d ON d.id = o.document_id
|
|
218
|
-
JOIN content_chunks c ON c.mirror_hash = o.mirror_hash AND c.seq = o.seq
|
|
219
|
-
JOIN vector_variants v ON v.variant_id = o.variant_id AND v.partition_id = o.partition_id
|
|
220
|
-
JOIN ${tableName} x ON x.variant_id = v.variant_id AND x.embedding = v.embedding
|
|
221
|
-
WHERE ${conditions.join(" AND ")}
|
|
222
|
-
AND (o.document_id || ':' || o.seq) IN (SELECT value FROM json_each(?))
|
|
223
|
-
GROUP BY v.variant_id, o.mirror_hash, o.seq
|
|
224
|
-
ORDER BY distance, o.mirror_hash, o.seq, v.variant_id LIMIT ?
|
|
225
|
-
`)
|
|
226
|
-
.all(
|
|
227
|
-
encodeEmbedding(embedding),
|
|
194
|
+
// Owner eligibility precedes ranking/LIMIT. Grouping before the distance
|
|
195
|
+
// keeps embedding blobs out of the group sorter.
|
|
196
|
+
const ranked = db.query<
|
|
197
|
+
{
|
|
198
|
+
mirrorHash: string;
|
|
199
|
+
seq: number;
|
|
200
|
+
inputHash: string;
|
|
201
|
+
distance: number;
|
|
202
|
+
documentIds: string;
|
|
203
|
+
},
|
|
204
|
+
(Uint8Array | string | number)[]
|
|
205
|
+
>(`
|
|
206
|
+
SELECT g.mirrorHash, g.seq, v.input_hash AS inputHash,
|
|
207
|
+
vec_distance_cosine(v.embedding, ?) AS distance, g.documentIds
|
|
208
|
+
FROM (
|
|
209
|
+
SELECT o.variant_id AS variantId, o.mirror_hash AS mirrorHash, o.seq,
|
|
210
|
+
json_group_array(o.document_id) AS documentIds
|
|
211
|
+
FROM vector_owners o
|
|
212
|
+
JOIN (${eligible.sql}) e ON e.id = o.document_id AND e.mirror_hash = o.mirror_hash
|
|
213
|
+
JOIN content_chunks c ON c.mirror_hash = o.mirror_hash AND c.seq = o.seq
|
|
214
|
+
WHERE ${conditions.join(" AND ")}
|
|
215
|
+
GROUP BY o.variant_id, o.mirror_hash, o.seq
|
|
216
|
+
) g
|
|
217
|
+
JOIN vector_variants v ON v.variant_id = g.variantId AND v.partition_id = ?
|
|
218
|
+
ORDER BY distance, g.mirrorHash, g.seq, g.variantId LIMIT ?
|
|
219
|
+
`);
|
|
220
|
+
const owners = db.query<
|
|
221
|
+
{ id: number; title: string | null; text: string },
|
|
222
|
+
[string, number, string]
|
|
223
|
+
>(`
|
|
224
|
+
SELECT d.id, d.title, c.text FROM documents d
|
|
225
|
+
JOIN content_chunks c ON c.mirror_hash = ? AND c.seq = ?
|
|
226
|
+
WHERE d.id IN (SELECT value FROM json_each(?))
|
|
227
|
+
`);
|
|
228
|
+
// A vector counts only while it matches its owner's current formatted
|
|
229
|
+
// input. Proving candidates in rank order and skipping unproven owners
|
|
230
|
+
// returns exactly what filtering every owner before ranking would.
|
|
231
|
+
const proofs = provenOwners(db);
|
|
232
|
+
const queryVector = encodeEmbedding(embedding);
|
|
233
|
+
let limit = k;
|
|
234
|
+
let results: VectorSearchResult[] = [];
|
|
235
|
+
for (;;) {
|
|
236
|
+
const rows = ranked.all(
|
|
237
|
+
queryVector,
|
|
228
238
|
...eligible.params,
|
|
229
239
|
...params,
|
|
230
|
-
|
|
231
|
-
|
|
240
|
+
partitionId,
|
|
241
|
+
limit
|
|
232
242
|
);
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
(row)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
243
|
+
results = [];
|
|
244
|
+
for (const row of rows) {
|
|
245
|
+
const documentIds = JSON.parse(row.documentIds) as number[];
|
|
246
|
+
const key = (id: number) =>
|
|
247
|
+
`${model}\0${id}\0${row.mirrorHash}\0${row.seq}\0${row.inputHash}`;
|
|
248
|
+
const unknown = documentIds.filter((id) => !proofs.has(key(id)));
|
|
249
|
+
if (unknown.length > 0) {
|
|
250
|
+
for (const owner of owners.all(
|
|
251
|
+
row.mirrorHash,
|
|
252
|
+
row.seq,
|
|
253
|
+
JSON.stringify(unknown)
|
|
254
|
+
)) {
|
|
255
|
+
proofs.set(
|
|
256
|
+
key(owner.id),
|
|
257
|
+
embeddingInputHash(
|
|
258
|
+
formatDocForEmbedding(owner.text, owner.title ?? undefined, model)
|
|
259
|
+
) === row.inputHash
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const proven = documentIds.filter((id) => proofs.get(key(id)));
|
|
264
|
+
if (proven.length === 0) continue;
|
|
265
|
+
results.push({
|
|
266
|
+
mirrorHash: row.mirrorHash,
|
|
267
|
+
seq: row.seq,
|
|
268
|
+
distance: row.distance,
|
|
269
|
+
documentIds: proven,
|
|
270
|
+
});
|
|
271
|
+
if (results.length === k) break;
|
|
272
|
+
}
|
|
273
|
+
if (results.length === k || rows.length < limit) break;
|
|
274
|
+
limit *= 4;
|
|
275
|
+
}
|
|
276
|
+
return results.filter(
|
|
277
|
+
(row) =>
|
|
278
|
+
options.minScore === undefined || 1 - row.distance >= options.minScore
|
|
279
|
+
);
|
|
242
280
|
}
|
|
243
281
|
|
|
244
282
|
/** Keep eligibility, provenance validation and ranking on one SQLite snapshot. */
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
e42897b28d0fc0fca7d1d7aca6ab016255cc3b5bf20d38bcac51535499eb7f25 gno-browser-clipper-v2.10.1.zip
|