Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
*.sh text eol=lf
02-tmcra-memory-api/deploy/tmcra text eol=lf
*.py text eol=lf
*.ps1 text eol=lf
*.js text eol=lf
*.mjs text eol=lf
*.ts text eol=lf
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ jobs:
- name: Verify portable service and model substitution
working-directory: 02-tmcra-memory-api
run: python -m unittest test_portable_release.py test_tmcra_service_model_flexibility.py
- name: Verify feedback and local-runtime safety contracts
working-directory: 02-tmcra-memory-api
run: python -m unittest discover -s tmcra_service/tests -q
- name: Run frozen benchmark contracts
working-directory: 09-tmcra-benchmarks
env:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ tmcra_service_state/
03-tmcra-web-console/public/downloads/tmcra-codex-*.zip
03-tmcra-web-console/desktop/tmcra-memory/resources/tmcra-codex-*
04-tmcra-desktop/resources/tmcra-codex-*
release/
docs/LOCAL_DEPLOYMENT_PRODUCTION_AUDIT.zh-CN.md
132 changes: 132 additions & 0 deletions 01-tmcra-agent-memory-algorithm/deploy/local-model-profiles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
{
"schema_version": "tmcra.local-model-profiles.1",
"verified_upstream_on": "2026-09-06",
"status": "windows_local_preview_partial_validation",
"installation_enabled": true,
"scope": "full_local_runtime_preview",
"full_memory_system_ready": false,
"hardware_requirements_are": "conservative_planning_estimates_not_benchmark_results",
"profiles": [
{
"id": "lite-cpu",
"name_zh": "轻量版",
"recommendation_zh": "普通笔记本、无独显电脑;中英文短记忆,低并发",
"validation": "cpu_ingest_and_raw_recall_passed_complex_compile_timed_out",
"system_ram_gib_min": 8,
"system_ram_gib_recommended_for_full_memory": 16,
"retrieval_vram_gib_recommended": 0,
"weights_bytes": 941234298,
"embedding": {
"repo_id": "intfloat/multilingual-e5-small",
"revision": "614241f622f53c4eeff9890bdc4f31cfecc418b3",
"license": "MIT",
"upstream": "https://huggingface.co/intfloat/multilingual-e5-small",
"weights": [{"file": "model.safetensors", "bytes": 470641600, "sha256": "1a55775f53449dac10a2bcbc312469fac40b96d53198c407081a831f81c98477"}],
"dimensions": 384,
"model_max_tokens": 512,
"pooling": "mean",
"normalize": true,
"query_prefix": "query: ",
"document_prefix": "passage: ",
"padding_side": "right"
},
"reranker": {
"repo_id": "cross-encoder/mmarco-mMiniLMv2-L12-H384-v1",
"revision": "1427fd652930e4ba29e8149678df786c240d8825",
"license": "Apache-2.0",
"upstream": "https://huggingface.co/cross-encoder/mmarco-mMiniLMv2-L12-H384-v1",
"weights": [{"file": "model.safetensors", "bytes": 470592698, "sha256": "5daeca2481a76b5976a2bdc32f0a78532b6716da4f8cd3ff59460ef8d2f359b4"}],
"adapter": "sequence-classification",
"model_max_tokens": 512,
"tmcra_fusion_checkpoint_compatible": false
},
"required_work": ["memory_pressure_retest", "complex_compile_latency", "organizer_validation", "full_service_restart_validation"]
},
{
"id": "balanced-bge",
"name_zh": "均衡版",
"recommendation_zh": "优先复现现有生产检索模型;16GB 以上内存,建议有独显",
"validation": "production_model_stack_verified_consumer_installer_pending",
"system_ram_gib_min": 16,
"system_ram_gib_recommended_for_full_memory": 32,
"retrieval_vram_gib_recommended": 6,
"weights_bytes": 4542217682,
"embedding": {
"repo_id": "BAAI/bge-m3",
"revision": "5617a9f61b028005a4858fdac845db406aefb181",
"license": "MIT",
"upstream": "https://huggingface.co/BAAI/bge-m3",
"weights": [{"file": "pytorch_model.bin", "bytes": 2271145830, "sha256": "b5e0ce3470abf5ef3831aa1bd5553b486803e83251590ab7ff35a117cf6aad38"}],
"dimensions": 1024,
"model_max_tokens": 8192,
"pooling": "cls",
"normalize": true,
"query_prefix": "",
"document_prefix": "",
"padding_side": "right"
},
"reranker": {
"repo_id": "BAAI/bge-reranker-v2-m3",
"revision": "953dc6f6f85a1b2dbfca4c34a2796e7dde08d41e",
"license": "Apache-2.0",
"upstream": "https://huggingface.co/BAAI/bge-reranker-v2-m3",
"weights": [{"file": "model.safetensors", "bytes": 2271071852, "sha256": "d9e3e081faff1eefb84019509b2f5558fd74c1a05a2c7db22f74174fcedb5286"}],
"adapter": "sequence-classification",
"model_max_tokens": 8192,
"production_runtime_max_tokens": 1280,
"tmcra_fusion_checkpoint_compatible": true
},
"required_work": ["single_recall_lane", "desktop_worker_and_context_budgets", "desktop_installer", "offline_end_to_end_validation"]
},
{
"id": "quality-qwen",
"name_zh": "增强版候选",
"recommendation_zh": "32GB 以上内存、高显存电脑;长文本和跨语言检索候选,需与均衡版实测比较",
"validation": "upstream_artifacts_verified_runtime_pending",
"system_ram_gib_min": 32,
"system_ram_gib_recommended_for_full_memory": 64,
"retrieval_vram_gib_recommended": 16,
"weights_bytes": 9235180368,
"embedding": {
"repo_id": "Qwen/Qwen3-Embedding-4B",
"revision": "5cf2132abc99cad020ac570b19d031efec650f2b",
"license": "Apache-2.0",
"upstream": "https://huggingface.co/Qwen/Qwen3-Embedding-4B",
"weights": [
{"file": "model-00001-of-00002.safetensors", "bytes": 4965826464, "sha256": "e70bfe3c970523fb7ef4eddffed2254ce3f1e7150c3de2af4342de129dd756f8"},
{"file": "model-00002-of-00002.safetensors", "bytes": 3077765624, "sha256": "ed1b87c8e9eb7e535a1a155e4fd00d9f4dba80e58a6db48a4c9f82cede7079c1"}
],
"dimensions": 2560,
"model_max_tokens": 32768,
"pooling": "last_token",
"normalize": true,
"query_prefix": "Instruct: Given a query about previous conversations, retrieve the relevant source passages.\nQuery: ",
"document_prefix": "",
"padding_side": "left"
},
"reranker": {
"repo_id": "Qwen/Qwen3-Reranker-0.6B",
"revision": "e61197ed45024b0ed8a2d74b80b4d909f1255473",
"license": "Apache-2.0",
"upstream": "https://huggingface.co/Qwen/Qwen3-Reranker-0.6B",
"weights": [{"file": "model.safetensors", "bytes": 1191588280, "sha256": "27cd75a405b9c1b46b59abfd88aaa209e6fed2a1972cde9b70e7659537c5e65b"}],
"adapter": "causal-lm-yes-no",
"model_max_tokens": 32768,
"tmcra_fusion_checkpoint_compatible": false
},
"required_work": ["qwen_yes_no_reranker_adapter", "service_variable_embedding_dimensions", "bounded_gpu_batches", "full_index_rebuild", "quality_and_latency_comparison"]
}
],
"deployment_contract": {
"automatic_profile_switch_on_existing_index": false,
"cloud_fallback_in_full_local_mode": false,
"cloud_account_required_in_full_local_mode": false,
"generation_model_included_in_weights_bytes": false,
"model_cache_and_python_runtime_included_in_weights_bytes": false,
"required_index_identity": ["repo_id", "revision", "dimensions", "pooling", "query_prefix", "document_prefix", "normalization", "precision", "chunking_policy"],
"existing_sources_must_be_preserved": true,
"existing_indexes_must_be_rebuilt_before_activation": true,
"runtime_downloads_after_setup": false,
"readiness_requires_actual_inference": true
}
}
7 changes: 7 additions & 0 deletions 01-tmcra-agent-memory-algorithm/run_tmcra_v4_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def _stage(root: Path, name: str, **values: Any) -> None:


def _load_shell_environment(path: Path) -> dict[str, str]:
from tmcra_local_only import enabled, read_environment
if enabled():
return read_environment(path)
if not path.is_file():
raise BuildError(f"writer environment file is missing: {path}")
command = 'set -a; source "$1"; env -0'
Expand Down Expand Up @@ -82,6 +85,10 @@ def _rotated(keys: Sequence[str], worker_index: int) -> str:

def _worker_environment(base: Mapping[str, str], keys: Sequence[str], worker_index: int) -> dict[str, str]:
environment = dict(base)
from tmcra_local_only import enabled, validate_environment
if enabled(environment):
validate_environment(environment)
return environment
pool = _rotated(keys, worker_index)
base_url = environment.get("TMCRA_DEEPSEEK_WRITER_BASE_URL") or environment.get("TMCRA_WRITER_BASE_URL") or "https://api.deepseek.com/v1"
max_tokens = environment.get("TMCRA_WRITER_MAX_TOKENS", "16384")
Expand Down
26 changes: 17 additions & 9 deletions 01-tmcra-agent-memory-algorithm/shared_core_manifest.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
{
"schema_version": "tmcra.service.shared-core-manifest.1",
"service_version": "0.3.0-rc2",
"generated_on": "2026-08-17",
"service_version": "1.0.0-rc.1",
"generated_on": "2026-09-06",
"algorithm_files": [
{
"path": "prepare_tmcra_v4_e2e_data.py",
"sha256": "68bdd34631a0897730926b5f8f68b87ee7352900446baba62d1615c961a53c96"
},
{
"path": "run_tmcra_v4_build.py",
"sha256": "1ebc54751fcfea91bbd8ea019cac45ca79cf60ce229bf7249d0427955093f93e"
"sha256": "4172caaa4e5a9b75dc2dec7c8188e6f585376aecb41e4f08a2514b25193ee4b9"
},
{
"path": "run_tmcra_v4_compile_evidence.py",
"sha256": "e869c9069bb0c8ad66e7f9bf469f17526269450cd0f58981ec9676d524234166"
},
{
"path": "tmp_tmcra_v2_lme_pipeline.py",
"sha256": "22768faa73f61050373791179f83a33595b46a3d9fb35476ef8054222a446cbd"
"sha256": "7e1ade3b1902c14c405be975c99764b6fac4843bd3b2a8ace5185593ec2fe365"
},
{
"path": "tmcra_v2_lme_pipeline.py",
"sha256": "b09afe18bcc888f02cad2a0985698210ff172ba9b5e77d9b4405e4146fa6bc60"
},
{
"path": "tmcra_v3_online_runtime.py",
"sha256": "75186638496fe9271b711e0ba76cb93b232a5684e75b565dfe4721bf821c0a12"
"sha256": "18b55050ff04bc8235b6c5aa2d53adf891a793179b4478bf4cfdfd6038c7195d"
},
{
"path": "tmcra_v3_product_writer.py",
Expand All @@ -41,7 +41,7 @@
},
{
"path": "tmcra_v4_batch_writer.py",
"sha256": "352568d64d831dbb28a228e9cd898f688636330b13ac2ff99e5ed36226a4dbf2"
"sha256": "a46a3695b08a8a5bd205863a43c416340863976f274d851ed2db4d04f5c125f5"
},
{
"path": "tmcra_v4_cost_report.py",
Expand All @@ -53,15 +53,15 @@
},
{
"path": "tmcra_v4_evidence_planner.py",
"sha256": "99dd6cd40bd205a4e9f10bc748b05aff848e187c9ce5f5f6fca9237a9d32aa99"
"sha256": "dfe546149fc8a5596ed311032020f36737eab37290a9e69255d2fae0fd708c7a"
},
{
"path": "tmcra_v4_online_runtime.py",
"sha256": "4fee0d591cd4140353d0adf57287e93534607e06db7c92b5ab42fbb0afe45db2"
"sha256": "7ef1bb4ec78094fa166750b78b567079b7048ca52787cfbefd7e3aaf8a9a8a2e"
},
{
"path": "tmcra_v4_slow_graph.py",
"sha256": "985e2aab12eba2b96bd53cc05e7352412fb45bd3d9fee3a0a8213b26ff4dba0b"
"sha256": "7ebf6d258b85c9a463e55c0dcdc817e9fc27b42fc93af7abdf48e62ecf8acf42"
},
{
"path": "tmcra_v4_recall_planner.py",
Expand All @@ -78,6 +78,14 @@
{
"path": "tmcra_v4_typed_semantics.py",
"sha256": "367917528c80829a9b99ecebc1f9c533fb77f39753713b65abadbddb9c4e43e5"
},
{
"path": "tmcra_local_only.py",
"sha256": "16da1be2c9d8bf881481ea64a09de30b423e3c4c496017e0b693e0bd2ba45e05"
},
{
"path": "tmcra_local_models.py",
"sha256": "f464a241c7f7ca2f78a52f7c03d7157520795281ac5c7e01faeaea4606274fb4"
}
]
}
101 changes: 101 additions & 0 deletions 01-tmcra-agent-memory-algorithm/tmcra_local_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""Pinned retrieval profiles shared by the API and its real index workers."""
from __future__ import annotations

import hashlib
import json
import os
from pathlib import Path

PROFILE_FILE = Path(__file__).resolve().parent / "deploy" / "local-model-profiles.json"


def profiles():
return json.loads(PROFILE_FILE.read_text(encoding="utf-8"))["profiles"]


def profile_by_id(identity):
for profile in profiles():
if profile["id"] == identity:
return profile
raise ValueError("unknown local model profile")


def signature(profile):
# A model change, pooling change or window-policy change requires reindexing.
contract = {"embedding": profile["embedding"], "source_windows": "token-char-covered-v1",
"long_slow_embedding": "normalized-window-mean-v1"}
return hashlib.sha256(json.dumps(contract, sort_keys=True, separators=(",", ":")).encode()).hexdigest()


def apply_local_profile(args):
if os.getenv("TMCRA_DEPLOYMENT_MODE") != "local":
return args
profile = profile_by_id(os.environ["TMCRA_LOCAL_PROFILE"])
embed = profile["embedding"]
rerank = profile["reranker"]
args.embedding_profile_id = profile["id"]
args.embedding_index_signature = signature(profile)
args.embedding_model = os.environ["TMCRA_EMBEDDING_MODEL"]
args.cross_model = os.environ["TMCRA_CROSS_MODEL"]
args.text_dim = embed["dimensions"]
args.embedding_max_length = embed["model_max_tokens"]
args.embedding_pooling = embed["pooling"]
args.embedding_query_prefix = embed["query_prefix"]
args.embedding_document_prefix = embed["document_prefix"]
args.embedding_padding_side = embed["padding_side"]
args.embedding_strict_max_length = True
args.embedding_long_document_policy = "window_mean"
args.reranker_mode = "fusion" if rerank["tmcra_fusion_checkpoint_compatible"] else "semantic-only"
args.reranker_adapter = rerank["adapter"]
args.cross_max_length = min(rerank["model_max_tokens"], 1280)
args.cross_batch_size = 2 if args.device == "cpu" else 8
args.batch_size = 4 if args.device == "cpu" else 8
return args


def verify_index_identity(payload, args):
expected = getattr(args, "embedding_index_signature", "")
if expected and (payload.get("embedding_index_signature") != expected
or payload.get("text_dim") != args.text_dim):
raise RuntimeError("index embedding identity differs; rebuild into a new generation before recall")


def sha256_file(path):
digest = hashlib.sha256()
with Path(path).open("rb") as handle:
for block in iter(lambda: handle.read(8 * 1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()


def verify_weights(model, directory):
directory = Path(directory)
for asset in model["weights"]:
path = directory / asset["file"]
if (not path.is_file() or path.stat().st_size != asset["bytes"]
or sha256_file(path) != asset["sha256"]):
raise RuntimeError(f"model asset is missing or failed SHA-256 verification: {asset['file']}")


QWEN_SYSTEM = ("<|im_start|>system\nJudge whether the Document meets the requirements based on the Query "
"and the Instruct provided. Note that the answer can only be \"yes\" or \"no\"."
"<|im_end|>\n<|im_start|>user\n")
QWEN_SUFFIX = "<|im_end|>\n<|im_start|>assistant\n<think>\n\n</think>\n\n"


def qwen_rerank_windows(tokenizer, query, document, *, max_length):
prefix = QWEN_SYSTEM + ("<Instruct>: Given a query about previous conversations, retrieve the relevant "
f"source passages.\n<Query>: {query}\n<Document>: ")
head = tokenizer.encode(prefix, add_special_tokens=False)
tail = tokenizer.encode(QWEN_SUFFIX, add_special_tokens=False)
body = tokenizer.encode(document, add_special_tokens=False)
capacity = max_length - len(head) - len(tail)
if capacity < 32:
raise ValueError("reranker query leaves insufficient document context; shorten the query")
step = max(1, capacity - min(192, capacity // 4))
windows = []
for start in range(0, max(1, len(body)), step):
windows.append(head + body[start:start + capacity] + tail)
if start + capacity >= len(body):
break
return windows
Loading
Loading