Compare commits

..

4 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
1e0275ee08 Improve code clarity and add documentation about in-place modification
Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
2026-01-30 15:53:40 +00:00
copilot-swe-agent[bot]
3fa7389ba9 Add defensive checks for thought_signature modification
Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
2026-01-30 15:49:25 +00:00
copilot-swe-agent[bot]
84a3b1f465 Add thought_signature to Gemini function calls for API compatibility
Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
2026-01-30 15:47:56 +00:00
copilot-swe-agent[bot]
377d011da2 Initial plan 2026-01-30 15:44:33 +00:00
4 changed files with 57 additions and 10 deletions

View File

@@ -1,6 +1,6 @@
[project]
name = "langbot"
version = "4.8.2"
version = "4.8.1"
description = "Production-grade platform for building agentic IM bots"
readme = "README.md"
license-files = ["LICENSE"]

View File

@@ -1,3 +1,3 @@
"""LangBot - Production-grade platform for building agentic IM bots"""
__version__ = '4.8.2'
__version__ = '4.8.1'

View File

@@ -20,6 +20,24 @@ class GeminiChatCompletions(chatcmpl.OpenAIChatCompletions):
'timeout': 120,
}
def _add_thought_signature_to_messages(self, messages: list[dict]) -> list[dict]:
"""Add thought_signature to tool_calls in messages for Gemini API compatibility
Gemini API requires a thought_signature field in function call parts.
See: https://ai.google.dev/gemini-api/docs/thought-signatures
Note: This function modifies the dictionaries in the messages list in place.
"""
for msg in messages:
if 'tool_calls' in msg and msg['tool_calls']:
# Ensure we're working with a mutable copy of tool_calls
if not isinstance(msg['tool_calls'], list):
continue
for tool_call in msg['tool_calls']:
if isinstance(tool_call, dict) and 'thought_signature' not in tool_call:
tool_call['thought_signature'] = ''
return messages
async def _closure_stream(
self,
query: pipeline_query.Query,
@@ -42,6 +60,9 @@ class GeminiChatCompletions(chatcmpl.OpenAIChatCompletions):
# 设置此次请求中的messages
messages = req_messages.copy()
# Add thought_signature to tool_calls for Gemini compatibility
messages = self._add_thought_signature_to_messages(messages)
# 检查vision
for msg in messages:
if 'content' in msg and isinstance(msg['content'], list):
@@ -140,3 +161,29 @@ class GeminiChatCompletions(chatcmpl.OpenAIChatCompletions):
yield provider_message.MessageChunk(**chunk_data)
chunk_idx += 1
async def _closure(
self,
query: pipeline_query.Query,
req_messages: list[dict],
use_model: requester.RuntimeLLMModel,
use_funcs: list[resource_tool.LLMTool] = None,
extra_args: dict[str, typing.Any] = {},
remove_think: bool = False,
) -> tuple[provider_message.Message, dict]:
"""Override _closure to add thought_signature to messages"""
# Make a shallow copy to avoid mutating the caller's list
messages = req_messages.copy()
# Add thought_signature to tool_calls for Gemini compatibility
messages = self._add_thought_signature_to_messages(messages)
# Call parent implementation
return await super()._closure(
query=query,
req_messages=messages,
use_model=use_model,
use_funcs=use_funcs,
extra_args=extra_args,
remove_think=remove_think,
)

16
uv.lock generated
View File

@@ -1790,7 +1790,7 @@ wheels = [
[[package]]
name = "langbot"
version = "4.8.2"
version = "4.8.1"
source = { editable = "." }
dependencies = [
{ name = "aiocqhttp" },
@@ -1893,7 +1893,7 @@ requires-dist = [
{ name = "ebooklib", specifier = ">=0.18" },
{ name = "gewechat-client", specifier = ">=0.1.5" },
{ name = "html2text", specifier = ">=2024.2.26" },
{ name = "langbot-plugin", specifier = "==0.2.5" },
{ name = "langbot-plugin", specifier = "==0.2.4" },
{ name = "langchain", specifier = ">=0.2.0" },
{ name = "langchain-text-splitters", specifier = ">=0.0.1" },
{ name = "lark-oapi", specifier = ">=1.4.15" },
@@ -1916,7 +1916,7 @@ requires-dist = [
{ name = "pymilvus", specifier = ">=2.6.4" },
{ name = "pynacl", specifier = ">=1.5.0" },
{ name = "pypdf2", specifier = ">=3.0.1" },
{ name = "pyseekdb", specifier = "==1.0.0b7" },
{ name = "pyseekdb", specifier = ">=0.1.0" },
{ name = "python-docx", specifier = ">=1.1.0" },
{ name = "python-socks", specifier = ">=2.7.1" },
{ name = "python-telegram-bot", specifier = ">=22.0" },
@@ -1949,7 +1949,7 @@ dev = [
[[package]]
name = "langbot-plugin"
version = "0.2.5"
version = "0.2.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiofiles" },
@@ -1967,9 +1967,9 @@ dependencies = [
{ name = "watchdog" },
{ name = "websockets" },
]
sdist = { url = "https://files.pythonhosted.org/packages/28/0e/117dfc00f36323cce2369be5176d5cd5247ff52edb34791413af9623f290/langbot_plugin-0.2.5.tar.gz", hash = "sha256:a1bf04c1c07b30c72fb9b28e1330372bb4a43ae2db309394435fc088c513cfd5", size = 103910 }
sdist = { url = "https://files.pythonhosted.org/packages/fc/5b/20941924d5ec9153c7ce236d9fa41874fa782cc7cd7303b22a8a11184168/langbot_plugin-0.2.4.tar.gz", hash = "sha256:319bdb2b809add762eb74b25787388f4adc9b34843511c59a47c175ee4de8eb1", size = 103713 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b1/0e/19b9a427206fa46aafbff03437296e38f425365c9ea6a97cbcfa791da2f8/langbot_plugin-0.2.5-py3-none-any.whl", hash = "sha256:b784248fc1f4754cd143bd9a16a7abd89a5c9735a4aa2b03c1c1e771b7d361e9", size = 133362 },
{ url = "https://files.pythonhosted.org/packages/79/0b/0e5375828e458083b264c69eb7b1d5ccb9e2a8d307977263964cacfe1b09/langbot_plugin-0.2.4-py3-none-any.whl", hash = "sha256:9f186c654727a04d3236dff27639501cae160797c70b3bcc76dc7d8641b5055e", size = 133150 },
]
[[package]]
@@ -4013,7 +4013,7 @@ wheels = [
[[package]]
name = "pyseekdb"
version = "1.0.0b7"
version = "1.0.0b8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -4026,7 +4026,7 @@ dependencies = [
{ name = "tqdm" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/92/6a/a0d4728de90e028a60a3583e6e96579087f0cf793e705ea7898a1490541c/pyseekdb-1.0.0b7-py3-none-any.whl", hash = "sha256:e32920636c345bc73adf03040f9bcb1ecc420d652cedae1558999cce19a67d52", size = 60927 },
{ url = "https://files.pythonhosted.org/packages/59/ab/f7f4c1c5a9c4b3dc772e5767c62530db904512ab9c3b6766761a9dfdf784/pyseekdb-1.0.0b8-py3-none-any.whl", hash = "sha256:7ffdec9025bf5719877eeb3ecff42bab1a4e06c7996e93d72023e2377fa0eba1", size = 58582 },
]
[[package]]