Skip to content

Commit 9f6c90b

Browse files
committed
GLM 4.6 support
1 parent 31fd661 commit 9f6c90b

4 files changed

Lines changed: 84 additions & 8 deletions

File tree

.env.example

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,17 @@ REFRAG_ENCODER_MODEL=BAAI/bge-base-en-v1.5
108108
REFRAG_PHI_PATH=/work/models/refrag_phi_768_to_dmodel.json
109109
REFRAG_SENSE=heuristic
110110

111-
# Llama.cpp sidecar (optional)
111+
# Llama.cpp sidecar (optional; REFRAG_RUNTIME=llamacpp)
112112
LLAMACPP_URL=http://llamacpp:8080
113113
REFRAG_DECODER_MODE=prompt # prompt|soft
114114

115115
REFRAG_SOFT_SCALE=1.0
116116

117+
# GLM API provider (alternative to llamacpp; REFRAG_RUNTIME=glm)
118+
GLM_API_KEY=
119+
GLM_API_BASE=https://api.z.ai/api/paas/v4/
120+
GLM_MODEL=glm-4.6
121+
117122

118123
# Operational safeguards and timeouts
119124
# Limit explosion of micro-chunks on huge files (0 to disable)

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ tree_sitter>=0.25.2
88
tree_sitter_languages; python_version < "3.13"
99
mcp==1.17.0
1010
fastmcp==2.12.4
11+
openai>=1.0
1112

1213
# Test-only
1314
pytest

scripts/mcp_indexer_server.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3312,21 +3312,29 @@ async def expand_query(query: Any = None, max_new: Any = None) -> Dict[str, Any]
33123312
cap = max(0, min(2, int(max_new)))
33133313
except (ValueError, TypeError):
33143314
cap = 2
3315-
from scripts.refrag_llamacpp import LlamaCppRefragClient, is_decoder_enabled # type: ignore
3316-
if not is_decoder_enabled():
3317-
return {"alternates": [], "hint": "decoder disabled: set REFRAG_DECODER=1 and start llamacpp (LLAMACPP_URL)"}
3315+
runtime = str(os.environ.get("REFRAG_RUNTIME", "llamacpp")).strip().lower()
3316+
dec_on = str(os.environ.get("REFRAG_DECODER", "0")).strip().lower() in {"1", "true", "yes", "on"}
3317+
if runtime == "glm":
3318+
if not (dec_on and os.environ.get("GLM_API_KEY")):
3319+
return {"alternates": [], "hint": "decoder disabled: set REFRAG_DECODER=1 and GLM_API_KEY; or use llamacpp"}
3320+
from scripts.refrag_glm import GLMRefragClient # type: ignore
3321+
client = GLMRefragClient()
3322+
else:
3323+
from scripts.refrag_llamacpp import LlamaCppRefragClient, is_decoder_enabled # type: ignore
3324+
if not is_decoder_enabled():
3325+
return {"alternates": [], "hint": "decoder disabled: set REFRAG_DECODER=1 and start llamacpp (LLAMACPP_URL)"}
3326+
client = LlamaCppRefragClient()
33183327
if not qlist:
33193328
return {"alternates": []}
33203329
prompt = (
33213330
"You expand code search queries. Given short queries, propose up to 2 compact alternates.\n"
33223331
"Return JSON array of strings only. No explanations.\n"
33233332
f"Queries: {qlist}\n"
33243333
)
3325-
client = LlamaCppRefragClient()
33263334
out = client.generate_with_soft_embeddings(
33273335
prompt=prompt,
33283336
max_tokens=int(os.environ.get("EXPAND_MAX_TOKENS", "64") or 64),
3329-
temperature=0.0, # Always 0 for deterministic expansion
3337+
temperature=0.0,
33303338
top_k=int(os.environ.get("EXPAND_TOP_K", "30") or 30),
33313339
top_p=float(os.environ.get("EXPAND_TOP_P", "0.9") or 0.9),
33323340
stop=["\n\n"],
@@ -4790,8 +4798,13 @@ def _ca_build_prompt(context_blocks: list[str], citations: list[Dict[str, Any]],
47904798

47914799

47924800
def _ca_decode(prompt: str, *, mtok: int, temp: float, top_k: int, top_p: float, stops: list[str]) -> str:
4793-
from scripts.refrag_llamacpp import LlamaCppRefragClient # type: ignore
4794-
client = LlamaCppRefragClient()
4801+
runtime = str(os.environ.get("REFRAG_RUNTIME", "llamacpp")).strip().lower()
4802+
if runtime == "glm":
4803+
from scripts.refrag_glm import GLMRefragClient # type: ignore
4804+
client = GLMRefragClient()
4805+
else:
4806+
from scripts.refrag_llamacpp import LlamaCppRefragClient # type: ignore
4807+
client = LlamaCppRefragClient()
47954808
return client.generate_with_soft_embeddings(
47964809
prompt=prompt,
47974810
max_tokens=mtok,

scripts/refrag_glm.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""
2+
Feature-flagged adapter for decoder-side ReFRAG using GLM (ZhipuAI).
3+
4+
Safe defaults:
5+
- Only used when REFRAG_DECODER=1 and REFRAG_RUNTIME=glm
6+
- Requires GLM_API_KEY; optionally configure GLM_MODEL
7+
"""
8+
from __future__ import annotations
9+
import os
10+
from typing import Any, Optional
11+
12+
13+
class GLMRefragClient:
14+
"""GLM client exposing generate_with_soft_embeddings(prompt, ...).
15+
16+
Notes:
17+
- soft_embeddings are ignored (GLM does not support KV/soft-embed injection)
18+
- prompt-mode only; mirrors llama.cpp adapter surface
19+
- Uses OpenAI SDK with custom base_url for GLM API
20+
"""
21+
22+
def __init__(self, api_key: Optional[str] = None, base_url: Optional[str] = None) -> None:
23+
self.api_key = api_key or os.environ.get("GLM_API_KEY", "").strip()
24+
if not self.api_key:
25+
raise ValueError("GLM_API_KEY is required when using REFRAG_RUNTIME=glm")
26+
self.base_url = base_url or os.environ.get("GLM_API_BASE", "https://api.z.ai/api/paas/v4/")
27+
from openai import OpenAI
28+
self.client = OpenAI(api_key=self.api_key, base_url=self.base_url)
29+
30+
def generate_with_soft_embeddings(
31+
self,
32+
prompt: str,
33+
soft_embeddings: Optional[list[list[float]]] = None, # unused
34+
max_tokens: int = 256,
35+
**gen_kwargs: Any,
36+
) -> str:
37+
model = os.environ.get("GLM_MODEL", "glm-4.6")
38+
temperature = float(gen_kwargs.get("temperature", 0.2))
39+
top_p = float(gen_kwargs.get("top_p", 0.95))
40+
stop = gen_kwargs.get("stop")
41+
42+
try:
43+
response = self.client.chat.completions.create(
44+
model=model,
45+
messages=[{"role": "user", "content": prompt}],
46+
max_tokens=int(gen_kwargs.get("max_tokens", max_tokens)),
47+
temperature=temperature,
48+
top_p=top_p,
49+
stop=stop if stop else None,
50+
)
51+
msg = response.choices[0].message
52+
# GLM-4.6 uses reasoning_content for thinking models
53+
content = getattr(msg, 'reasoning_content', None) or msg.content or ""
54+
return content.strip()
55+
except Exception as e:
56+
raise RuntimeError(f"GLM completion failed: {e}")
57+

0 commit comments

Comments
 (0)