@gmickel/gno 1.34.0 → 1.34.2
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 +1 -1
- package/browser-extension/artifacts/{gno-browser-clipper-v1.34.0.zip → gno-browser-clipper-v1.34.2.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.34.2.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +1 -1
- package/spec/cli.md +2 -0
- package/src/cli/commands/models/pull.ts +32 -3
- package/src/llm/nodeLlamaCpp/generation.ts +31 -3
- package/src/store/sqlite/adapter.ts +56 -91
- package/browser-extension/artifacts/gno-browser-clipper-v1.34.0.zip.sha256 +0 -1
package/README.md
CHANGED
|
@@ -117,7 +117,7 @@ gno daemon --detach # headless indexing + resident MCP gateway
|
|
|
117
117
|
|
|
118
118
|
<!-- public-truth:current-version -->
|
|
119
119
|
|
|
120
|
-
> Current release: **v1.34.
|
|
120
|
+
> Current release: **v1.34.1** — see [CHANGELOG.md](./CHANGELOG.md)
|
|
121
121
|
|
|
122
122
|
<!-- /public-truth -->
|
|
123
123
|
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ee0e3d4032a41a097c85fba552a9ab449906f258e14844ad5e3b5f99001716e0 gno-browser-clipper-v1.34.2.zip
|
package/package.json
CHANGED
package/spec/cli.md
CHANGED
|
@@ -1922,6 +1922,8 @@ gno models pull [--all|--embed|--rerank|--gen] [--force]
|
|
|
1922
1922
|
**Behavior:**
|
|
1923
1923
|
|
|
1924
1924
|
- Skips models that are already cached (checksum match) unless `--force` is used
|
|
1925
|
+
- Skips HTTP(S) rerank endpoints as external services; they are called directly
|
|
1926
|
+
and are never downloaded or cached, including with `--force`
|
|
1925
1927
|
- Default (no flags): pulls all models
|
|
1926
1928
|
|
|
1927
1929
|
**Exit Codes:**
|
|
@@ -10,6 +10,7 @@ import type { DownloadProgress, ModelType } from "../../../llm/types";
|
|
|
10
10
|
import { getModelsCachePath } from "../../../app/constants";
|
|
11
11
|
import { loadConfig } from "../../../config";
|
|
12
12
|
import { ModelCache } from "../../../llm/cache";
|
|
13
|
+
import { isHttpRerankUri } from "../../../llm/httpRerank";
|
|
13
14
|
import { getActivePreset } from "../../../llm/registry";
|
|
14
15
|
|
|
15
16
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -46,6 +47,7 @@ export interface ModelPullResult {
|
|
|
46
47
|
error?: string;
|
|
47
48
|
path?: string;
|
|
48
49
|
skipped?: boolean;
|
|
50
|
+
skipReason?: "cached" | "external";
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
export interface ModelsPullResult {
|
|
@@ -117,6 +119,20 @@ export async function modelsPull(
|
|
|
117
119
|
const uri =
|
|
118
120
|
type === "expand" ? (preset.expand ?? preset.gen) : preset[type];
|
|
119
121
|
|
|
122
|
+
// HTTP rerankers are services, not model artifacts. They are loaded
|
|
123
|
+
// directly by LlmAdapter and must never enter the local model cache path.
|
|
124
|
+
if (type === "rerank" && isHttpRerankUri(uri)) {
|
|
125
|
+
results.push({
|
|
126
|
+
type,
|
|
127
|
+
uri,
|
|
128
|
+
ok: true,
|
|
129
|
+
skipped: true,
|
|
130
|
+
skipReason: "external",
|
|
131
|
+
});
|
|
132
|
+
skipped += 1;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
120
136
|
// Check if already cached (skip unless --force)
|
|
121
137
|
if (!options.force) {
|
|
122
138
|
const isCached = await cache.isCached(uri);
|
|
@@ -128,6 +144,7 @@ export async function modelsPull(
|
|
|
128
144
|
ok: true,
|
|
129
145
|
path: path ?? undefined,
|
|
130
146
|
skipped: true,
|
|
147
|
+
skipReason: "cached",
|
|
131
148
|
});
|
|
132
149
|
skipped += 1;
|
|
133
150
|
continue;
|
|
@@ -176,13 +193,17 @@ export async function modelsPull(
|
|
|
176
193
|
*/
|
|
177
194
|
export function formatModelsPull(result: ModelsPullResult): string {
|
|
178
195
|
const lines: string[] = [];
|
|
196
|
+
let externalSkipped = 0;
|
|
179
197
|
const label = (type: ModelType) =>
|
|
180
198
|
type === "gen" ? "answer" : type === "expand" ? "expand" : type;
|
|
181
199
|
|
|
182
200
|
for (const r of result.results) {
|
|
183
201
|
if (r.ok) {
|
|
184
202
|
if (r.skipped) {
|
|
185
|
-
|
|
203
|
+
if (r.skipReason === "external") externalSkipped += 1;
|
|
204
|
+
const reason =
|
|
205
|
+
r.skipReason === "external" ? "external endpoint" : "already cached";
|
|
206
|
+
lines.push(`${label(r.type)}: skipped (${reason})`);
|
|
186
207
|
} else {
|
|
187
208
|
lines.push(`${label(r.type)}: downloaded`);
|
|
188
209
|
}
|
|
@@ -196,10 +217,18 @@ export function formatModelsPull(result: ModelsPullResult): string {
|
|
|
196
217
|
lines.push(`${result.failed} model(s) failed to download.`);
|
|
197
218
|
} else if (result.skipped === result.results.length) {
|
|
198
219
|
lines.push("");
|
|
199
|
-
lines.push(
|
|
220
|
+
lines.push(
|
|
221
|
+
externalSkipped > 0
|
|
222
|
+
? "No model downloads needed."
|
|
223
|
+
: "All models already cached. Use --force to re-download."
|
|
224
|
+
);
|
|
200
225
|
} else {
|
|
201
226
|
lines.push("");
|
|
202
|
-
lines.push(
|
|
227
|
+
lines.push(
|
|
228
|
+
externalSkipped > 0
|
|
229
|
+
? "All downloadable models downloaded successfully."
|
|
230
|
+
: "All models downloaded successfully."
|
|
231
|
+
);
|
|
203
232
|
}
|
|
204
233
|
|
|
205
234
|
return lines.join("\n");
|
|
@@ -60,6 +60,29 @@ const DEFAULT_TEMPERATURE = 0;
|
|
|
60
60
|
const DEFAULT_SEED = 42;
|
|
61
61
|
const DEFAULT_MAX_TOKENS = 256;
|
|
62
62
|
|
|
63
|
+
// Context sizing: without an explicit contextSize, node-llama-cpp defaults to
|
|
64
|
+
// "auto", which grows the KV cache to fill available VRAM up to the model's
|
|
65
|
+
// trained context length (OOM risk on small GPUs — see issue #189). Instead,
|
|
66
|
+
// size the context to what the call actually needs: prompt tokens + output
|
|
67
|
+
// budget + margin for chat-template wrapping and special tokens.
|
|
68
|
+
const GEN_CONTEXT_MARGIN_TOKENS = 512;
|
|
69
|
+
const GEN_CONTEXT_MIN_TOKENS = 1024;
|
|
70
|
+
|
|
71
|
+
export const resolveGenContextSize = (input: {
|
|
72
|
+
promptTokenCount: number;
|
|
73
|
+
maxTokens: number;
|
|
74
|
+
trainContextSize?: number;
|
|
75
|
+
}): number => {
|
|
76
|
+
const needed = Math.max(
|
|
77
|
+
GEN_CONTEXT_MIN_TOKENS,
|
|
78
|
+
input.promptTokenCount + input.maxTokens + GEN_CONTEXT_MARGIN_TOKENS
|
|
79
|
+
);
|
|
80
|
+
if (input.trainContextSize && input.trainContextSize > 0) {
|
|
81
|
+
return Math.min(needed, input.trainContextSize);
|
|
82
|
+
}
|
|
83
|
+
return needed;
|
|
84
|
+
};
|
|
85
|
+
|
|
63
86
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
64
87
|
// Implementation
|
|
65
88
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -97,9 +120,14 @@ export class NodeLlamaCppGeneration implements GenerationPort {
|
|
|
97
120
|
await this.manager.getLlama()
|
|
98
121
|
).createGrammarForJsonSchema(params.jsonSchema as JsonGrammarSchema)
|
|
99
122
|
: undefined;
|
|
100
|
-
|
|
101
|
-
params?.contextSize
|
|
102
|
-
|
|
123
|
+
const contextSize =
|
|
124
|
+
params?.contextSize ??
|
|
125
|
+
resolveGenContextSize({
|
|
126
|
+
promptTokenCount: llamaModel.tokenize(prompt).length,
|
|
127
|
+
maxTokens: params?.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
128
|
+
trainContextSize: llamaModel.trainContextSize,
|
|
129
|
+
});
|
|
130
|
+
context = await llamaModel.createContext({ contextSize });
|
|
103
131
|
// Import LlamaChatSession dynamically
|
|
104
132
|
const { LlamaChatSession } = await import("node-llama-cpp");
|
|
105
133
|
const session = new LlamaChatSession({
|
|
@@ -128,11 +128,7 @@ import {
|
|
|
128
128
|
classifyResolvedGraphEdge,
|
|
129
129
|
mergeGraphEdgeAudit,
|
|
130
130
|
} from "../../core/graph-edge-confidence";
|
|
131
|
-
import {
|
|
132
|
-
buildWikiBestMatchSubquery,
|
|
133
|
-
buildWikiBestRankMatchCountSubquery,
|
|
134
|
-
buildWikiBestRankSubquery,
|
|
135
|
-
} from "../../core/graph-resolver";
|
|
131
|
+
import { buildWikiBestMatchSubquery } from "../../core/graph-resolver";
|
|
136
132
|
import { buildContentPrefilterNeedles } from "../../core/link-relevance";
|
|
137
133
|
import { normalizeWikiName, stripWikiMdExt } from "../../core/links";
|
|
138
134
|
import {
|
|
@@ -179,6 +175,7 @@ import {
|
|
|
179
175
|
getLatestFileRefactorReceiptByPlanDigest as getStoredLatestFileRefactorReceiptByPlanDigest,
|
|
180
176
|
} from "./file-refactor-journal-store";
|
|
181
177
|
import { loadFts5Snowball } from "./fts5-snowball";
|
|
178
|
+
import { resolveGraphLinkTargets } from "./graph-link-resolver";
|
|
182
179
|
import { queryGraphNeighborsForSeeds } from "./graph-neighbors";
|
|
183
180
|
import {
|
|
184
181
|
appendExportManifest as appendStoredTraceExportManifest,
|
|
@@ -4757,9 +4754,13 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
4757
4754
|
match_count: number | null;
|
|
4758
4755
|
}
|
|
4759
4756
|
|
|
4760
|
-
interface
|
|
4757
|
+
interface GraphLinkResolutionRow {
|
|
4758
|
+
source_id: number;
|
|
4759
|
+
source_docid: string;
|
|
4760
|
+
source_collection: string;
|
|
4761
|
+
target_ref_norm: string;
|
|
4762
|
+
target_collection: string | null;
|
|
4761
4763
|
link_type: "wiki" | "markdown";
|
|
4762
|
-
unresolved: number;
|
|
4763
4764
|
}
|
|
4764
4765
|
|
|
4765
4766
|
interface NodeMetaRow {
|
|
@@ -4771,104 +4772,68 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
4771
4772
|
rel_path: string;
|
|
4772
4773
|
}
|
|
4773
4774
|
|
|
4774
|
-
const
|
|
4775
|
-
let
|
|
4775
|
+
const linkParams: string[] = [];
|
|
4776
|
+
let sourceCollectionClause = "";
|
|
4776
4777
|
if (collection) {
|
|
4777
|
-
|
|
4778
|
-
|
|
4778
|
+
sourceCollectionClause = "AND src.collection = ?";
|
|
4779
|
+
linkParams.push(collection);
|
|
4779
4780
|
}
|
|
4780
4781
|
|
|
4781
|
-
const
|
|
4782
|
+
const graphLinkRows = db
|
|
4783
|
+
.query<GraphLinkResolutionRow, string[]>(
|
|
4784
|
+
`
|
|
4782
4785
|
SELECT
|
|
4783
4786
|
src.id as source_id,
|
|
4784
4787
|
src.docid as source_docid,
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
dl.
|
|
4788
|
-
|
|
4789
|
-
WHEN 'wiki' THEN (${buildWikiBestRankSubquery(
|
|
4790
|
-
"COALESCE(dl.target_collection, src.collection)",
|
|
4791
|
-
"dl.target_ref_norm"
|
|
4792
|
-
)})
|
|
4793
|
-
WHEN 'markdown' THEN 5
|
|
4794
|
-
END as match_rank,
|
|
4795
|
-
CASE dl.link_type
|
|
4796
|
-
WHEN 'wiki' THEN (${buildWikiBestRankMatchCountSubquery(
|
|
4797
|
-
"COALESCE(dl.target_collection, src.collection)",
|
|
4798
|
-
"dl.target_ref_norm"
|
|
4799
|
-
)})
|
|
4800
|
-
WHEN 'markdown' THEN 1
|
|
4801
|
-
END as match_count
|
|
4788
|
+
src.collection as source_collection,
|
|
4789
|
+
dl.target_ref_norm,
|
|
4790
|
+
dl.target_collection,
|
|
4791
|
+
dl.link_type
|
|
4802
4792
|
FROM documents src
|
|
4803
4793
|
JOIN doc_links dl ON dl.source_doc_id = src.id
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
)})
|
|
4809
|
-
WHEN 'markdown' THEN (
|
|
4810
|
-
SELECT md.id FROM documents md
|
|
4811
|
-
WHERE md.active = 1
|
|
4812
|
-
AND md.collection = COALESCE(dl.target_collection, src.collection)
|
|
4813
|
-
AND md.rel_path = dl.target_ref_norm
|
|
4814
|
-
ORDER BY md.id LIMIT 1
|
|
4815
|
-
)
|
|
4816
|
-
END
|
|
4817
|
-
WHERE src.active = 1 AND tgt.active = 1
|
|
4818
|
-
${edgeCollectionClause}
|
|
4819
|
-
ORDER BY src.id ASC, tgt.id ASC, dl.link_type ASC
|
|
4820
|
-
`;
|
|
4821
|
-
|
|
4822
|
-
const resolvedEdgeRows = db
|
|
4823
|
-
.query<ResolvedEdgeRow, string[]>(resolvedEdgeQuery)
|
|
4824
|
-
.all(...edgeParams);
|
|
4825
|
-
|
|
4826
|
-
const unresolvedParams: string[] = [];
|
|
4827
|
-
let unresolvedCollectionClause = "";
|
|
4828
|
-
if (collection) {
|
|
4829
|
-
unresolvedCollectionClause = "AND src.collection = ?";
|
|
4830
|
-
unresolvedParams.push(collection);
|
|
4831
|
-
}
|
|
4832
|
-
const unresolvedQuery = `
|
|
4833
|
-
SELECT
|
|
4834
|
-
link_type,
|
|
4835
|
-
COUNT(*) as unresolved
|
|
4836
|
-
FROM (
|
|
4837
|
-
SELECT
|
|
4838
|
-
dl.link_type,
|
|
4839
|
-
CASE dl.link_type
|
|
4840
|
-
WHEN 'wiki' THEN (
|
|
4841
|
-
${buildWikiBestMatchSubquery(
|
|
4842
|
-
"COALESCE(dl.target_collection, src.collection)",
|
|
4843
|
-
"dl.target_ref_norm"
|
|
4844
|
-
)}
|
|
4845
|
-
)
|
|
4846
|
-
WHEN 'markdown' THEN (
|
|
4847
|
-
SELECT t.id FROM documents t
|
|
4848
|
-
WHERE t.active = 1
|
|
4849
|
-
AND t.collection = COALESCE(dl.target_collection, src.collection)
|
|
4850
|
-
AND t.rel_path = dl.target_ref_norm
|
|
4851
|
-
ORDER BY t.id LIMIT 1
|
|
4852
|
-
)
|
|
4853
|
-
END as target_id
|
|
4854
|
-
FROM documents src
|
|
4855
|
-
JOIN doc_links dl ON dl.source_doc_id = src.id
|
|
4856
|
-
WHERE src.active = 1
|
|
4857
|
-
${unresolvedCollectionClause}
|
|
4794
|
+
WHERE src.active = 1
|
|
4795
|
+
${sourceCollectionClause}
|
|
4796
|
+
ORDER BY src.id ASC, dl.id ASC
|
|
4797
|
+
`
|
|
4858
4798
|
)
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4799
|
+
.all(...linkParams);
|
|
4800
|
+
const resolutions = resolveGraphLinkTargets(
|
|
4801
|
+
db,
|
|
4802
|
+
graphLinkRows.map((row) => ({
|
|
4803
|
+
targetRefNorm: row.target_ref_norm,
|
|
4804
|
+
targetCollection: row.target_collection ?? row.source_collection,
|
|
4805
|
+
linkType: row.link_type,
|
|
4806
|
+
}))
|
|
4807
|
+
);
|
|
4808
|
+
const resolvedEdgeRows: ResolvedEdgeRow[] = [];
|
|
4865
4809
|
const unresolvedByType: Record<"wiki" | "markdown", number> = {
|
|
4866
4810
|
wiki: 0,
|
|
4867
4811
|
markdown: 0,
|
|
4868
4812
|
};
|
|
4869
|
-
for (const row of
|
|
4870
|
-
|
|
4813
|
+
for (const [index, row] of graphLinkRows.entries()) {
|
|
4814
|
+
const resolution = resolutions[index];
|
|
4815
|
+
if (!resolution) {
|
|
4816
|
+
unresolvedByType[row.link_type] += 1;
|
|
4817
|
+
continue;
|
|
4818
|
+
}
|
|
4819
|
+
const targetCollection = row.target_collection ?? row.source_collection;
|
|
4820
|
+
if (collection && targetCollection !== collection) continue;
|
|
4821
|
+
resolvedEdgeRows.push({
|
|
4822
|
+
source_id: row.source_id,
|
|
4823
|
+
source_docid: row.source_docid,
|
|
4824
|
+
target_id: resolution.targetId,
|
|
4825
|
+
target_docid: resolution.targetDocid,
|
|
4826
|
+
link_type: row.link_type,
|
|
4827
|
+
match_rank: resolution.matchRank,
|
|
4828
|
+
match_count: resolution.matchCount,
|
|
4829
|
+
});
|
|
4871
4830
|
}
|
|
4831
|
+
resolvedEdgeRows.sort(
|
|
4832
|
+
(left, right) =>
|
|
4833
|
+
left.source_id - right.source_id ||
|
|
4834
|
+
left.target_id - right.target_id ||
|
|
4835
|
+
left.link_type.localeCompare(right.link_type)
|
|
4836
|
+
);
|
|
4872
4837
|
const totalEdgesUnresolved =
|
|
4873
4838
|
unresolvedByType.wiki + unresolvedByType.markdown;
|
|
4874
4839
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0acc125d848721bdced540fe49412ef8c83df5d4ff3ba086076c46ed9d441998 gno-browser-clipper-v1.34.0.zip
|