Skip to content

feat(light-version): merge light-version into master with LangChain v1.2 upgrade#25

Merged
tea9296 merged 14 commits intomasterfrom
light-version
Feb 26, 2026
Merged

feat(light-version): merge light-version into master with LangChain v1.2 upgrade#25
tea9296 merged 14 commits intomasterfrom
light-version

Conversation

@stoday
Copy link
Copy Markdown
Collaborator

@stoday stoday commented Feb 25, 2026

Summary

This PR merges light-version into master as part of the AKASHA upgrade.
It introduces the light edition (feature set + installation path), upgrades LangChain to v1.2, and shifts model execution to a remote API-only approach.

Key Changes

Added light edition functionality and installation flow
Upgraded langchain to v1.2
Removed heavyweight dependencies used for local model inference
Simplified runtime model access to remote API calls only
Updated related integration/configuration logic for the new architecture

Why This Change

Reduce package size and dependency complexity
Improve install experience and maintenance cost
Standardize inference path through remote model services
Avoid local model runtime overhead in the light edition

Validation

Light installation flow verified
Core remote-API model invocation paths tested
Critical workflows validated after LangChain v1.2 migration
No unintended file changes included in this PR

Impact

Light edition no longer supports local model execution dependencies
Model calls in light edition are routed through remote APIs only
Existing users relying on local inference should remain on non-light/full setup

Risks & Rollback

Potential Risks

  • Behavior differences from LangChain v1.2 migration
  • Runtime failures if remote API credentials/endpoints are misconfigured
  • Edge-case regressions in chain/tool integrations

Rollback Plan

  • Revert this PR as a single unit if regression is found
  • Temporarily use pre-merge full setup for local model workflows

Reviewer Notes

  • Prioritize review on:
    • LangChain v1.2 migration changes
    • dependency removals related to local inference
    • remote API model invocation flow in light edition
  • Merge after CI is green and core scenarios are confirmed

stoday and others added 11 commits January 3, 2026 11:01
… management with improved ChromaDB (v0.6.3) data handling and reduced logging noise.
- 優化 logging_config,當 verbose 和 keep_logs 皆為 False 時將日誌等級設為 WARNING。
- 降低 httpx 與 google.genai 等第三方套件的日誌噪音。
- 更新 gemini_model,直接使用 Google GenAI SDK 的 count_tokens 進行字數統計。
- 重構 gemini_model 的 call 方法,優化非串流回應的處理邏輯。
- 針對 agents.py 進行小幅重構與程式碼清理。
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR merges the “light-version” work into master as part of the AKASHA upgrade: introducing a light install path intended to avoid heavyweight local-inference dependencies, upgrading LangChain to the v1.x import/layout, and shifting more flows to remote API usage.

Changes:

  • Added “light vs full” docs, light requirements, and a new GitHub Actions CI workflow.
  • Migrated LangChain imports to langchain_core / langchain_text_splitters and updated various integrations accordingly.
  • Refactored multiple local-model / scoring / rerank code paths to fail gracefully when optional heavyweight dependencies are missing, and added new upgrade test scaffolding.

Reviewed changes

Copilot reviewed 67 out of 76 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
upgrade_light_version.md Documents the intended light/full packaging split and upgrade plan.
tests/upgrade_tests/conftest.py Loads .env for upgrade test runs.
tests/upgrade_tests/test_openai_rag.py Adds OpenAI light-mode RAG smoke test and placeholders for dependency checks.
tests/upgrade_tests/test_gemini_rag.py Adds Gemini RAG smoke test.
tests/upgrade_tests/test_anthropic_rag.py Adds Anthropic RAG smoke test.
tests/upgrade_tests/test_light_restrictions.py Adds tests intended to validate missing-dependency behavior in light mode.
tests/tests_data/docs/simple_case.json Adds structured fixture data for agent/API tests.
tests/test_summary.py Updates summary test to use Gemini + env_file wiring.
tests/test_eval.py Updates eval test to use Gemini embeddings/model and conditionally skip if bert_score missing.
tests/test_db.py Updates DB test embeddings to Gemini and loads env vars.
tests/test_api_stability.py Adds broader API stability smoke tests (ask/RAG/agent/vision/memory).
tests/test_akasha.py Updates core tests to Gemini defaults and propagates env_file into RAG/ask.
tests/test_agents_observation_normalization.py Adds regression test for non-string tool observation handling.
tests/test_agent.py Updates agent test to pass env_file and normalizes formatting.
tests.md Adds/updates test planning doc for light vs full scope and known issues.
requirements.txt Updates LangChain-related requirement set for the upgrade (full-style requirements).
requirements-light.txt Introduces a “light” requirements set intended to avoid heavy local inference deps.
pyproject.toml Moves to LangChain v1.x deps and attempts to model light/full extras and optional heavyweight deps.
akasha/utils/search/search_doc.py Migrates Document/BaseRetriever imports to langchain_core.
akasha/utils/search/retrievers/retri_tfidf.py Migrates Document import to langchain_core.
akasha/utils/search/retrievers/retri_svm.py Migrates embeddings/retriever/document imports to langchain_core.
akasha/utils/search/retrievers/retri_rerank.py Adds optional-dependency guarding for rerank (torch/transformers) + LangChain import updates.
akasha/utils/search/retrievers/retri_mmr.py Migrates embeddings/retriever/document imports to langchain_core.
akasha/utils/search/retrievers/retri_knn.py Migrates embeddings/retriever/document imports to langchain_core.
akasha/utils/search/retrievers/retri_faiss.py Migrates embeddings/retriever/document imports to langchain_core.
akasha/utils/search/retrievers/retri_custom.py Migrates embeddings/retriever/document imports to langchain_core.
akasha/utils/search/retrievers/retri_bm25.py Migrates retriever/document imports to langchain_core.
akasha/utils/search/retrievers/base.py Migrates retriever import and adds rerank fallback behavior when deps are missing.
akasha/utils/prompts/format.py Migrates Document import to langchain_core.
akasha/utils/models/remo.py Migrates LLM base import to LangChain core.
akasha/utils/models/llamacpp2.py Adds graceful ImportError if llama-cpp-python is missing + LangChain core import update.
akasha/utils/models/hf.py Adds try/except guards for torch/transformers and raises clearer error when torch missing + LangChain core import update.
akasha/utils/models/gtq.py Adds try/except guards for torch/transformers + LangChain core import update.
akasha/utils/models/gemi.py Updates LangChain imports, pydantic config style, and Gemini call/token counting behavior.
akasha/utils/models/custom.py Migrates embeddings/LLM imports to langchain_core and updates doc example import path.
akasha/utils/models/chglm.py Migrates LLM import to LangChain core.
akasha/utils/models/azure_openai.py Migrates LLM import to LangChain core.
akasha/utils/models/anthro.py Migrates LLM import to LangChain core.
akasha/utils/logging_config.py Adjusts root log level based on verbose/keep_logs and reduces third-party noise.
akasha/utils/db/load_docs.py Migrates Document import to langchain_core.
akasha/utils/db/file_loader.py Migrates Document import to langchain_core.
akasha/utils/db/db_structure.py Improves robustness for ChromaDB return types (numpy arrays/None) and normalizes to lists.
akasha/utils/db/create_db.py Migrates Document + text splitter imports to LangChain core/text-splitters.
akasha/tools/summary.py Migrates Document + text splitter imports to LangChain core/text-splitters.
akasha/tools/ask.py Migrates Document import to LangChain core.
akasha/helper/web_engine.py Migrates Document import to LangChain core.
akasha/helper/self_query_filter.py Migrates AttributeInfo import to langchain_classic.
akasha/helper/scores.py Adds ImportError messaging when bert_score/transformers are missing.
akasha/helper/memory.py Adds env_file parameter and propagates it to model/embedding handling + DB loading.
akasha/helper/handle_objects.py Wraps imports for optional heavyweight deps and raises clearer “install [full]” errors.
akasha/helper/base.py Migrates Document import to LangChain core.
akasha/eval/model_eval.py Adds clearer ImportError messaging when torch is missing + LangChain import update.
akasha/eval/evaluation.py Adds early-return handling for empty question sets and guards BERTScore averaging.
akasha/agent/base.py Migrates BaseTool import to langchain_core.tools.
akasha/agent/agents.py Normalizes observation to strings and refactors streaming path to use call_stream_model.
akasha/agent/agent_tools.py Migrates BaseTool import to langchain_core.tools.
akasha/init.py Sets Chroma telemetry opt-out env var and keeps optional auto logging configuration.
.gitignore Updates ignores for pytest cache, test env files, and memory test artifacts.
.github/workflows/ci.yml Adds GitHub Actions CI job using uv + .[light,dev] + pytest.
Comments suppressed due to low confidence (1)

akasha/utils/models/hf.py:70

  • transformers imports are guarded at module import time by setting AutoTokenizer/AutoModelForCausalLM/... = None, but __init__ only checks torch is None. If torch is present but transformers is missing, this will fail later with an AttributeError when calling AutoTokenizer.from_pretrained(...). Add an explicit check for the transformers symbols being None and raise a clear ImportError pointing users to pip install akasha-terminal[full].
        if torch is None:
            raise ImportError(
                "Feature requiring 'torch' is not installed. Please install with: pip install akasha-terminal[full]"
            )
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        if temperature == 0.0:
            temperature = 0.01
        if "max_output_tokens" in kwargs:
            self.max_output_tokens = kwargs["max_output_tokens"]

        self.temperature = temperature
        self.model_name = model_name
        if "vision" in model_name.lower():
            self.init_vision_model()
        else:
            self.tokenizer = AutoTokenizer.from_pretrained(
                model_name, token=self.hf_token
            )
            self.streamer = TextIteratorStreamer(self.tokenizer, skip_prompt=True)
            self.model = AutoModelForCausalLM.from_pretrained(

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +41 to +57
def test_no_torch_imported():
"""
Test that importing akasha and running a basic OpenAI task
does not pull in torch if we are in 'light' mode.
"""
# This test is a placeholder for the logic that will verify torch is not loaded.
# We can check sys.modules after a fresh import in a subprocess.
pass

def test_graceful_failure_local_model():
"""
Test that trying to use a local model without torch/transformers
raises a clear ImportError.
"""
# Once refactored, this should raise ImportError if torch is not installed.
# For now, it might still try to import torch.
pass
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_no_torch_imported and test_graceful_failure_local_model are currently empty (pass), so they will always succeed and won’t actually validate the light-mode constraints described in the docstring. Either implement the assertions now (e.g., using a subprocess to check sys.modules / an isolated venv) or mark them pytest.skip/xfail until the refactor is complete to avoid a false sense of coverage.

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +15
with patch.dict(sys.modules, {'torch': None, 'transformers': None}):
import akasha.helper.handle_objects as handle_objects
importlib_reload(handle_objects) # Ensure fresh state if possible

with pytest.raises(ImportError) as excinfo:
handle_objects.handle_model("hf:any-model")

assert "Feature requiring 'torch/transformers' is not installed" in str(excinfo.value)
assert "pip install akasha-terminal[full]" in str(excinfo.value)
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Patching sys.modules with {'torch': None, 'transformers': None} does not reliably simulate “module not installed” (Python may treat the entry as a loaded module, so import torch won’t raise ImportError). This can make the test pass/fail for the wrong reasons. Consider patching importlib.util.find_spec to return None, or patching builtins.__import__ to raise ModuleNotFoundError for the target modules, to ensure the code path actually raises ImportError as intended.

Copilot uses AI. Check for mistakes.
Comment thread akasha/agent/agents.py
Comment on lines +226 to +227
result = asyncio.run(collect_non_stream())
return result
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__call__ uses asyncio.run(...) for the non-streaming path. This raises RuntimeError: asyncio.run() cannot be called from a running event loop in common environments (Jupyter, async frameworks, some test runners). Consider detecting an existing running loop and using await self.acall(...) in async contexts (or providing a separate sync wrapper that uses anyio.from_thread / nest_asyncio-style compatibility), instead of unconditionally calling asyncio.run.

Suggested change
result = asyncio.run(collect_non_stream())
return result
# Avoid calling asyncio.run() if we're already inside a running event loop.
try:
asyncio.get_running_loop()
except RuntimeError:
# No running event loop: safe to use asyncio.run
result = asyncio.run(collect_non_stream())
return result
else:
# Running event loop detected: __call__ cannot safely block here.
# In async contexts, use `await acall(...)` instead of `__call__`.
raise RuntimeError(
"__call__ cannot be used from within an active asyncio event loop. "
"Use 'await acall(...)' in asynchronous contexts."
)

Copilot uses AI. Check for mistakes.
Comment thread akasha/__init__.py
Comment thread pyproject.toml
Comment on lines +71 to 93
[project.optional-dependencies]
light = []
full = [
"langchain-huggingface>=0.1.2",
"onnxruntime<=1.20.0",
"sentence-transformers>=3.1.1",
"transformers>=4.50.0",
"accelerate>=1.7.0",
"bert-score==0.3.13",
"tokenizers>=0.19.1",
"sentencepiece",
"torch==2.2.0; platform_system == 'Windows'",
"torch==2.0.1; platform_system == 'Darwin'",
"torch==2.2.0; platform_system == 'Linux'",

"torchvision==0.17.0; platform_system == 'Windows'",
"torchvision==0.15.2; platform_system == 'Darwin'",
"torchvision==0.17.0; platform_system == 'Linux'",
"llama-cpp-python>=0.3.8",
"auto-gptq==0.3.1",
]

[project.optional-dependencies]
llama-cpp = ["llama-cpp-python>=0.3.8"]
peft = ["auto-gptq==0.3.1"]
dev = ["pytest", "pytest-cov"]
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

peft_Llama2 imports peft, but neither the full extra nor the peft extra lists peft as a dependency (the peft extra currently only includes auto-gptq). This will cause runtime ImportErrors even after installing .[full]. Add peft to the appropriate optional-dependency set(s), or remove/guard the feature if it’s intentionally unsupported.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +38
with patch.dict(sys.modules, {'torch': None}):
from akasha.utils.search.retrievers.base import get_retrivers
from akasha.utils.db.db_structure import dbs

mock_db = MagicMock(spec=dbs)
mock_db.get_Documents.return_value = []

# This should print a warning but not crash, returning whatever retrievers it could find
# Since we only ask for rerank and it fails, it might raise ValueError later if list is empty
with patch('builtins.print') as mock_print:
with pytest.raises(ValueError): # No retrievers found because rerank was skipped
get_retrivers(
mock_db,
"gemini:gemini-embedding-001",
search_type="rerank",
)

# Check if warning was printed
warning_called = any("pip install akasha-terminal[full]" in args[0] for args, _ in mock_print.call_args_list)
assert warning_called
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here: patch.dict(sys.modules, {'torch': None}) may not trigger the ImportError branch in get_retrivers (since import torch can succeed with a None entry), so the warning/assertions can become unreliable. Use an import-hook style patch (e.g., patch find_spec / __import__) to force an ImportError and verify the fallback behavior deterministically.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/ci.yml
Comment on lines +26 to +27
- name: Run pytest
run: pytest --maxfail=1 --disable-warnings -q
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow runs the full pytest suite after installing .[light,dev], but many tests in this repo make real external API calls (OpenAI/Gemini/etc.). That makes CI flaky/costly and will fail for PRs from forks (secrets won’t be available). Consider splitting unit vs integration tests (e.g., marker-based selection), and only run integration tests when secrets are present and the PR comes from a trusted context.

Suggested change
- name: Run pytest
run: pytest --maxfail=1 --disable-warnings -q
- name: Run unit tests
run: pytest -m "not integration" --maxfail=1 --disable-warnings -q
- name: Run integration tests (requires secrets, non-fork)
if: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) && (secrets.OPENAI_API_KEY != '' || secrets.GEMINI_API_KEY != '') }}
run: pytest -m "integration" --maxfail=1 --disable-warnings -q

Copilot uses AI. Check for mistakes.
Comment thread akasha/eval/evaluation.py
if self.question_style.lower() == "essay":
return 0.0, 0.0, 0.0, self.doc_tokens
return 0.0, self.doc_tokens
progress = tqdm(total=self.question, desc=f"Run Eval({self.question_style})")
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tqdm(total=self.question, ...) looks incorrect here: self.question was just reset to [] a few lines above, so total will be a list (or empty list) rather than an integer, which will raise a TypeError in tqdm for non-empty runs. This should likely be tqdm(total=self.question_num, ...) (or len(question)).

Suggested change
progress = tqdm(total=self.question, desc=f"Run Eval({self.question_style})")
progress = tqdm(total=self.question_num, desc=f"Run Eval({self.question_style})")

Copilot uses AI. Check for mistakes.
Comment thread pyproject.toml
Comment on lines +51 to +68
# 重度相依 (預設安裝,除非指定 [light] )
"langchain-huggingface>=0.1.2; extra != 'light'",
"onnxruntime<=1.20.0; extra != 'light'",
"sentence-transformers>=3.1.1; extra != 'light'",
"transformers>=4.50.0; extra != 'light'",
"accelerate>=1.7.0; extra != 'light'",
"bert-score==0.3.13; extra != 'light'",
"tokenizers>=0.19.1; extra != 'light'",
"sentencepiece; extra != 'light'",

# 各平台 Torch/torchvision
"torch==2.2.0; platform_system == 'Windows' and extra != 'light'",
"torch==2.0.1; platform_system == 'Darwin' and extra != 'light'",
"torch==2.2.0; platform_system == 'Linux' and extra != 'light'",

"torchvision==0.17.0; platform_system == 'Windows' and extra != 'light'",
"torchvision==0.15.2; platform_system == 'Darwin' and extra != 'light'",
"torchvision==0.17.0; platform_system == 'Linux' and extra != 'light'",
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dependencies uses markers like extra != 'light' to try to exclude heavyweight deps when installing .[light]. Extras can only add optional requirements; they can’t subtract base dependencies, and the extra marker is typically unset/empty when evaluating core deps—so these heavy packages will still be selected (and may even be treated as invalid markers by some tooling). To make a real light install, move heavy deps out of [project].dependencies entirely and put them only under [project.optional-dependencies].full (and document that default install is full vs light via a separate distribution or different install target).

Copilot uses AI. Check for mistakes.
Comment thread akasha/agent/agents.py
Comment on lines +410 to +420
try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
if loop.is_running():
import concurrent.futures
with concurrent.futures.ThreadPoolExecutor() as pool:
firsthand_observation = pool.submit(asyncio.run, result).result()
else:
firsthand_observation = loop.run_until_complete(result)
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In async _run_agent, coroutine tool results should be awaited (firsthand_observation = await result). The current implementation spins up/uses event loops and even runs the coroutine via asyncio.run in a thread pool when a loop is already running, which can deadlock, break contextvars, and fail for coroutines bound to the current loop. Simplify this branch to await result inside _run_agent (and keep the more complex handling only in the sync streaming path if needed).

Suggested change
try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
if loop.is_running():
import concurrent.futures
with concurrent.futures.ThreadPoolExecutor() as pool:
firsthand_observation = pool.submit(asyncio.run, result).result()
else:
firsthand_observation = loop.run_until_complete(result)
firsthand_observation = await result

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 25, 2026

@stoday I've opened a new pull request, #26, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits February 25, 2026 08:25
Co-authored-by: stoday <5661087+stoday@users.noreply.github.com>
Fix contradictory bert-score classification in upgrade_light_version.md
@tea9296 tea9296 merged commit e648f3e into master Feb 26, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants