Skip to content

Commit 865c994

Browse files
anvansterclaude
andcommitted
feat(embed): static-model telemetry + release-independent model fetch
- Telemetry: mcp.start now emits `embeddingModel` (static / bge-small / jina-code-v2 / granite-97m) via EmbeddingBackend::telemetry_id — static adoption is queryable in PostHog (and the extension config snapshot already reports the setting now that 'static' is valid). - scripts/fetch-static-model.sh: fetch the distilled model from the release-independent `model` GitHub release (package-time bundle or manual). - MCP postinstall: best-effort static-model fetch (skip via CODEGRAPH_SKIP_MODEL_FETCH; never fails install). - VS Code: default CODEGRAPH_STATIC_MODEL to the bundled bin/jina-code-static-256 when embeddingModel=static and staticModelPath is unset. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 1ce7c7e commit 865c994

6 files changed

Lines changed: 78 additions & 2 deletions

File tree

crates/codegraph-memory/src/embedding/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ impl EmbeddingBackend {
6969
),
7070
}
7171
}
72+
73+
/// Short, stable tag for telemetry / adoption grouping.
74+
pub fn telemetry_id(&self) -> &'static str {
75+
match self {
76+
Self::Static(_) => "static",
77+
Self::Fastembed(CodeGraphEmbeddingModel::BgeSmall) => "bge-small",
78+
Self::Fastembed(CodeGraphEmbeddingModel::JinaCodeV2) => "jina-code-v2",
79+
Self::Fastembed(CodeGraphEmbeddingModel::Granite97mMultilingualR2) => "granite-97m",
80+
}
81+
}
7282
}
7383

7484
/// Resolve the static-model directory: `CODEGRAPH_STATIC_MODEL` env override,

crates/codegraph-server/src/mcp/server.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,7 @@ impl McpServer {
13951395
"os": std::env::consts::OS,
13961396
"arch": std::env::consts::ARCH,
13971397
"version": crate::metadata::VERSION,
1398+
"embeddingModel": self.backend.memory_manager.embedding_telemetry_id(),
13981399
}));
13991400

14001401
loop {

crates/codegraph-server/src/memory.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@ impl MemoryManager {
208208
}
209209
}
210210

211+
/// Short telemetry tag for the configured embedding backend
212+
/// (`static` / `bge-small` / `jina-code-v2` / `granite-97m`).
213+
pub fn embedding_telemetry_id(&self) -> &'static str {
214+
self.embedding_model.telemetry_id()
215+
}
216+
211217
/// Initialize the memory manager with workspace path
212218
///
213219
/// Resolves the global data directory at `~/.codegraph/projects/<slug>/memory/`,

mcp-package/bin/postinstall.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,30 @@ try {
5757
console.warn(` ${err.message}`);
5858
}
5959

60+
// Fetch the distilled static embedding model (best-effort) from the
61+
// release-independent `model` GitHub release. Only needed for
62+
// `--embedding-model static`; skipped if already present or if
63+
// CODEGRAPH_SKIP_MODEL_FETCH is set. Never fails the install.
64+
if (!process.env.CODEGRAPH_SKIP_MODEL_FETCH) {
65+
const MODEL = "jina-code-static-256";
66+
const modelDir = path.join(os.homedir(), ".codegraph", "static_models", MODEL);
67+
if (!fs.existsSync(path.join(modelDir, "model.safetensors"))) {
68+
try {
69+
fs.mkdirSync(modelDir, { recursive: true });
70+
const url = `https://github.com/codegraph-ai/CodeGraph/releases/download/model/${MODEL}.tar.gz`;
71+
const tgz = path.join(modelDir, "_model.tar.gz");
72+
execFileSync("curl", ["-fsSL", url, "-o", tgz], { timeout: 180000 });
73+
execFileSync("tar", ["xzf", tgz, "-C", modelDir], { timeout: 60000 });
74+
fs.unlinkSync(tgz);
75+
console.log(`✓ codegraph-mcp: static embedding model ready (${modelDir})`);
76+
} catch {
77+
console.warn(
78+
`ℹ codegraph-mcp: static model not fetched (optional — only for --embedding-model static)`
79+
);
80+
}
81+
}
82+
}
83+
6084
// Hint about the optional Claude Code hook. Installation is opt-in to avoid
6185
// silently modifying the user's ~/.claude/settings.json. Both Unix
6286
// (bash) and Windows (PowerShell) variants are shipped — the installer

scripts/fetch-static-model.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env bash
2+
# Fetch the distilled static embedding model from the release-independent
3+
# `model` GitHub release (decoupled from versioned releases — bumping the app
4+
# version never requires re-uploading the model).
5+
#
6+
# Used two ways:
7+
# • Package time — place the model into the VS Code extension bundle:
8+
# scripts/fetch-static-model.sh vscode/bin/jina-code-static-256
9+
# • Manually — populate the server's default resolve path:
10+
# scripts/fetch-static-model.sh
11+
#
12+
# Usage: scripts/fetch-static-model.sh [DEST_DIR] [MODEL_NAME]
13+
# DEST_DIR default ~/.codegraph/static_models/<MODEL_NAME>
14+
# MODEL_NAME default jina-code-static-256
15+
#
16+
# Expects a `<MODEL_NAME>.tar.gz` asset on the `model` release whose contents
17+
# are the model files at the archive root, created with:
18+
# tar czf jina-code-static-256.tar.gz -C <model-dir> .
19+
set -euo pipefail
20+
21+
MODEL="${2:-jina-code-static-256}"
22+
DEST="${1:-$HOME/.codegraph/static_models/$MODEL}"
23+
URL="https://github.com/codegraph-ai/CodeGraph/releases/download/model/${MODEL}.tar.gz"
24+
25+
mkdir -p "$DEST"
26+
echo "fetching ${MODEL}.tar.gz -> $DEST"
27+
curl -fsSL "$URL" | tar xz -C "$DEST"
28+
29+
if [ ! -f "$DEST/model.safetensors" ]; then
30+
echo "error: model.safetensors missing after extract — check the '$MODEL' release asset" >&2
31+
exit 1
32+
fi
33+
echo "static model ready: $(ls "$DEST" | tr '\n' ' ')"

vscode/src/extension.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,10 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
299299
const wsFolder = vscode.workspace.workspaceFolders?.[0]?.uri;
300300
const cfg = vscode.workspace.getConfiguration('codegraph', wsFolder);
301301
const spawnEnv = { ...process.env };
302-
const staticModelPath = cfg.get<string>('staticModelPath');
303-
if (cfg.get<string>('embeddingModel') === 'static' && staticModelPath) {
302+
if (cfg.get<string>('embeddingModel') === 'static') {
303+
// staticModelPath override, else the model bundled next to the binary.
304+
const staticModelPath = cfg.get<string>('staticModelPath')
305+
|| path.join(context.extensionPath, 'bin', 'jina-code-static-256');
304306
spawnEnv.CODEGRAPH_STATIC_MODEL = staticModelPath;
305307
}
306308
const child = cp.spawn(serverModule, [], { cwd: context.extensionPath, env: spawnEnv });

0 commit comments

Comments
 (0)