From 8c53e3e39992f7a8296d24fc1a9bc5b94d180392 Mon Sep 17 00:00:00 2001 From: ktz03 <2484593937@qq.com> Date: Wed, 14 Oct 2026 18:27:29 +0800 Subject: [PATCH 1/2] fix(langchain): extract text blocks in viking_store --- .../src/langchain_openviking/tools.py | 6 +- tests/unit/test_langchain_integration.py | 79 ++++++++++++++++++- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/examples/langchain/src/langchain_openviking/tools.py b/examples/langchain/src/langchain_openviking/tools.py index 87d764b0e4..ac1c904d89 100644 --- a/examples/langchain/src/langchain_openviking/tools.py +++ b/examples/langchain/src/langchain_openviking/tools.py @@ -25,6 +25,7 @@ call_openviking, compact_json, ensure_client, + extract_message_text, item_value, iter_result_items, stringify, @@ -683,7 +684,10 @@ def _normalize_messages(messages: str | list[dict[str, Any]]) -> list[dict[str, } ) continue - content = str(message.get("content", "")) + raw_content = message.get("content", "") + content = ( + extract_message_text(raw_content) if isinstance(raw_content, list) else str(raw_content) + ) if role == "tool": normalized.append( { diff --git a/tests/unit/test_langchain_integration.py b/tests/unit/test_langchain_integration.py index e9321a1611..d20bc7b290 100644 --- a/tests/unit/test_langchain_integration.py +++ b/tests/unit/test_langchain_integration.py @@ -11,7 +11,13 @@ pytest.importorskip("langchain_openviking") import langchain_openviking.client as client_helpers -from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, ToolMessage +from langchain_core.messages import ( + AIMessage, + HumanMessage, + SystemMessage, + ToolMessage, + convert_to_openai_messages, +) from langchain_core.runnables import RunnableLambda from langchain_openviking import ( InMemoryOpenVikingClient, @@ -176,6 +182,77 @@ def test_create_openviking_tools_exposes_common_viking_primitives(): assert "VikingDB is internal vector/index storage" in health +@pytest.mark.parametrize("role", ["user", "assistant", "system", "tool"]) +@pytest.mark.parametrize("text_format", ["string", "block"]) +def test_viking_store_normalizes_langchain_text_blocks(role: str, text_format: str): + content = [ + {"type": "text", "text": "Remember cobalt deployment."}, + {"type": "text", "text": "中文确认"}, + ] + messages = { + "user": HumanMessage(content=content), + "assistant": AIMessage(content=content), + "system": SystemMessage(content=content), + "tool": ToolMessage(content=content, tool_call_id="call-normal", name="ordinary_tool"), + } + wire = convert_to_openai_messages([messages[role]], text_format=text_format) + client = InMemoryOpenVikingClient() + store = create_openviking_tools(client=client, tool_names=["viking_store"])[0] + + result = json.loads( + store.invoke({"session_id": "text-blocks", "messages": wire, "commit": False}) + ) + + assert result["messages_added"] == 1 + stored = client.sessions["text-blocks"][0] + assert stored["role"] == ("assistant" if role in {"system", "tool"} else role) + part = stored["parts"][0] + assert ( + part["tool_output" if role == "tool" else "text"] == "Remember cobalt deployment.\n中文确认" + ) + if role == "tool": + assert part["tool_id"] == "call-normal" + assert part["tool_name"] == "ordinary_tool" + assert part["tool_status"] == "completed" + + +@pytest.mark.parametrize("content", [None, False, 0]) +def test_viking_store_preserves_scalar_content(content: Any): + client = InMemoryOpenVikingClient() + store = create_openviking_tools(client=client, tool_names=["viking_store"])[0] + + store.invoke( + { + "session_id": "scalar", + "messages": [{"role": "user", "content": content}], + "commit": False, + } + ) + + assert client.sessions["scalar"][0]["parts"] == [{"type": "text", "text": str(content)}] + + +@pytest.mark.parametrize("role", ["user", "system", "tool"]) +def test_viking_store_preserves_native_parts(role: str): + client = InMemoryOpenVikingClient() + store = create_openviking_tools(client=client, tool_names=["viking_store"])[0] + parts = [{"type": "text", "text": "explicit parts control"}] + + store.invoke( + { + "session_id": "native-parts", + "messages": [ + {"role": role, "content": [{"type": "text", "text": "unused"}], "parts": parts} + ], + "commit": False, + } + ) + + stored = client.sessions["native-parts"][0] + assert stored["role"] == ("assistant" if role in {"system", "tool"} else role) + assert stored["parts"] == parts + + def test_create_openviking_tools_uses_peer_id_only_for_message_attribution(): client = InMemoryOpenVikingClient( {"viking://~/memories/profile.md": "The peer likes LangGraph agents."} From a7956233dabf998ff4b0ca3146cd5a6e4aeeb9a1 Mon Sep 17 00:00:00 2001 From: ktz03 <2484593937@qq.com> Date: Sun, 18 Oct 2026 23:16:14 +0800 Subject: [PATCH 2/2] test(langchain): align integration imports with package lint context --- .../langchain/tests/unit/test_langchain_integration.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/integrations/frameworks/langchain/tests/unit/test_langchain_integration.py b/integrations/frameworks/langchain/tests/unit/test_langchain_integration.py index d20bc7b290..8370cb5ca8 100644 --- a/integrations/frameworks/langchain/tests/unit/test_langchain_integration.py +++ b/integrations/frameworks/langchain/tests/unit/test_langchain_integration.py @@ -10,7 +10,6 @@ pytest.importorskip("langgraph") pytest.importorskip("langchain_openviking") -import langchain_openviking.client as client_helpers from langchain_core.messages import ( AIMessage, HumanMessage, @@ -19,6 +18,10 @@ convert_to_openai_messages, ) from langchain_core.runnables import RunnableLambda +from langgraph.store.base import PutOp +from openviking_sdk.errors import InvalidArgumentError + +import langchain_openviking.client as client_helpers from langchain_openviking import ( InMemoryOpenVikingClient, OpenVikingChatMessageHistory, @@ -42,8 +45,6 @@ ) from langchain_openviking.middleware import _message_signature from langchain_openviking.tools import _archive_grep_pattern, _resolve_resource_source -from langgraph.store.base import PutOp -from openviking_sdk.errors import InvalidArgumentError def test_langchain_client_exposes_apply_commit_policy_without_legacy_alias():