Compare commits

...

50 Commits

Author SHA1 Message Date
朱潮
2964326cb8 update to deepagents 0.5.2 2026-04-11 16:23:59 +08:00
朱潮
ed34ff9ee9 Merge branch 'prod' into developing 2026-04-11 16:08:16 +08:00
朱潮
a9044c6d2e TOOL_OUTPUT_MAX_LENGTH 扩展 2026-04-11 13:31:45 +08:00
朱潮
7d22f0b34d 禁止路径穿越 2026-04-11 11:48:18 +08:00
朱潮
788bb0089f upgrade to deepagents-0_5_2 2026-04-11 11:40:43 +08:00
朱潮
b6976cc8bf Merge branch 'onprem-release' into developing 2026-04-11 10:42:08 +08:00
朱潮
f67d18e13f Merge branch 'onprem-dev' into developing 2026-04-11 10:42:00 +08:00
朱潮
6813a48a99 Merge branch 'dev' into developing 2026-04-11 10:41:51 +08:00
朱潮
4d75075406 Merge branch 'prod' into developing 2026-04-11 10:39:37 +08:00
朱潮
675d7d3e12 Merge branch 'onprem-dev' into onprem-release 2026-04-11 10:38:56 +08:00
朱潮
4625ddf5a9 merge from dev 2026-04-11 10:38:26 +08:00
朱潮
5b7522eff2 merge guideline-assistant-message-error 2026-04-09 16:59:56 +08:00
朱潮
aae1742b37 merge guideline-assistant-message-error 2026-04-09 16:59:06 +08:00
朱潮
d1e31953b0 merge guideline-assistant-message-error 2026-04-09 15:05:11 +08:00
朱潮
513dda8bbb 🐛 fix: 修复 GuidelineMiddleware 导致 assistant message prefill 报错
enable_thinking 开启时,thinking 中间件将 AIMessage 追加到 messages 末尾,
导致不支持 assistant prefill 的模型返回 400 错误。
修复方式:在 AIMessage 后追加多语言 HumanMessage,确保消息以 user 结尾。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 15:02:28 +08:00
朱潮
b23412b84b Merge branch 'feature/pre-memory-prompt' into onprem-release 2026-04-03 11:59:37 +08:00
朱潮
c4a0ce1162 Merge branch 'feature/pre-memory-prompt' into onprem-dev 2026-04-03 11:55:53 +08:00
朱潮
ab6b68268e Merge branch 'feature/pre-memory-prompt' into dev 2026-04-02 17:49:21 +08:00
朱潮
845815866e Merge branch 'feature/pre-memory-prompt' into dev 2026-04-02 16:49:32 +08:00
朱潮
76e742e7b3 merge FACT_RETRIEVAL_PROMPT.md 2026-04-02 16:45:29 +08:00
朱潮
738a904a6f merge 2026-04-02 11:25:20 +08:00
autobee-sparticle
213e541697
fix: resolve PrePrompt Hook env var crash and increase Mem0 pool size (#24)
1. Fix "all environment values must be bytes or str" error in hook execution
   by ensuring all env values are converted to str (getattr may return None
   when attribute exists but is None). Also sanitize shell_env values.

2. Increase MEM0_POOL_SIZE default from 20 to 50 to address "connection pool
   exhausted" errors under high concurrency.

Fixes: sparticleinc/felo-mygpt#2519

Co-authored-by: zhuchao <zhuchaowe@163.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 22:04:31 +09:00
朱潮
44db634cbb Merge branch 'feature/moshui20260330-schedule-job' into dev 2026-04-01 10:37:16 +08:00
朱潮
89a9d81892 Merge branch 'feature/moshui20260330-schedule-job' into dev 2026-03-31 20:56:29 +08:00
朱潮
dc2e8a39e3 Merge branch 'feature/moshui20260330-schedule-job' into dev 2026-03-31 20:04:49 +08:00
朱潮
2bc071645f merge from onprem 2026-03-30 21:22:19 +08:00
朱潮
52a700e0db Merge branch 'onprem-release' into dev 2026-03-30 21:21:37 +08:00
朱潮
7214adcf8e Merge branch 'dev' of https://github.com/sparticleinc/catalog-agent into dev 2026-03-30 21:02:05 +08:00
朱潮
dc52ddb8cc Merge branch 'feature/pre-memory-prompt' into dev 2026-03-30 21:00:45 +08:00
autobee-sparticle
0c9c36cc54
fix: 禁止 NOVARE 设备控制二次确认循环 (#22)
* add page number

* feat: add skill feature memory

添加 skill 功能的 feature memory,记录技能包管理服务和 Hook 系统的核心信息。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(skill): add feature memory with changelog and decisions

添加 skill 功能的完整记忆文档:

Changelog:
- 2025-Q4: 初始实现 (GRPC 层 + 内置 skills)
- 2026-Q1: API 完善 (REST API + Hook 系统)

Design Decisions:
- 001: Skill 架构设计 (目录结构、Hook 系统)
- 002: 上传安全措施 (ZipSlip、路径遍历防护)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* soffice sharp 支持

* shell_env support

* fix: 禁止 NOVARE 设备控制二次确认循环

- 添加"禁止二次确认"最高优先级规则,明确用户确认后必须立即执行工具调用
- 扩展确认关键词列表,增加更多日语确认表达(お願いします、はい、うん等)
- 添加正确/错误流程示例,防止模型循环询问确认
- 强化规则指南中的确认执行逻辑

Fixes: sparticleinc/mygpt-frontend#2303

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: 朱潮 <zhuchaowe@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: zhuchao <zhuchaowe@163.com>
2026-03-27 18:34:12 +09:00
朱潮
6b6fad9c1c Merge branch 'onprem-dev' into onprem-release 2026-03-27 15:08:37 +08:00
朱潮
d0b619f4f1 Merge branch 'onprem' into onprem-dev 2026-03-27 12:31:32 +08:00
朱潮
6300eea61d refactor: 将 citation 详细提示词从 system prompt 移至 RAG tool result 按需注入
system prompt 中的 citation 规则(document/table/web 三类约80行)占用大量 token,
现将详细格式要求移到 rag_retrieve_server.py 中作为工具返回前缀按需注入,
system prompt 仅保留精简版通用 placement rules。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:30:20 +08:00
朱潮
becd36da9d 增加高亮功能 2026-03-27 12:12:50 +08:00
autobee-sparticle
18bf296aa0
feat: move enable_thinking control from docker-compose to request body (#21)
* add page number

* feat: add skill feature memory

添加 skill 功能的 feature memory,记录技能包管理服务和 Hook 系统的核心信息。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(skill): add feature memory with changelog and decisions

添加 skill 功能的完整记忆文档:

Changelog:
- 2025-Q4: 初始实现 (GRPC 层 + 内置 skills)
- 2026-Q1: API 完善 (REST API + Hook 系统)

Design Decisions:
- 001: Skill 架构设计 (目录结构、Hook 系统)
- 002: 上传安全措施 (ZipSlip、路径遍历防护)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* soffice sharp 支持

* shell_env support

* feat: move enable_thinking control from docker-compose to request body

Remove DEFAULT_THINKING_ENABLE environment variable from docker-compose
and settings.py. The enable_thinking flag is now solely controlled via
request body (default: false), as felo-mygpt already passes this config
from RobotConfig database.

Closes sparticleinc/felo-mygpt#2473

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: 朱潮 <zhuchaowe@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: zhuchao <zhuchaowe@163.com>
2026-03-26 20:12:39 +09:00
autobee-sparticle
85519da5a5
fix(memory): 改进 Memory 提取 prompt 使用大白话 (#20)
将 fact extraction prompt 中的技术性格式改为自然语言:
- "Contact: [name] (relationship, referred as [nick])" → "[name] is a [relationship], also called [nick]"
- 移除 "DEFAULT when user says" 等技术标记
- 添加 Plain Language Rule 明确要求输出通俗易懂的文本
- 更新所有示例为自然语言风格

Co-authored-by: zhuchao <zhuchaowe@163.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 10:14:13 +09:00
autobee-sparticle
e987cb6f6b
fix(novare): 添加位置粒度降级搜索策略,解决详细位置指定时设备匹配失败问题 (#18)
当用户指定过于详细的位置信息(如"3階執務スペース、フォーラム側窓側")时,
find_device_by_area 可能无法匹配到设备区域。新增降级搜索策略:
- 第1步:去除方位修饰语,保留核心区域名重新搜索
- 第2步:进一步简化到楼层级别搜索
- 降级成功时告知用户搜索范围变化并确认

Closes #2201 (mygpt-frontend)

Co-authored-by: zhuchao <zhuchaowe@163.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 15:47:48 +09:00
朱潮
e713a0a903 Merge branch 'prod' into onprem 2026-03-18 15:40:52 +08:00
朱潮
f9839b9bc4 Merge branch 'prod' into onprem-release 2026-03-18 15:40:50 +08:00
朱潮
2adc8fc5e3 Merge branch 'prod' into dev
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 15:40:43 +08:00
朱潮
4b3cab0cc7 Merge branch 'prod' into onprem-dev 2026-03-18 15:38:08 +08:00
朱潮
cc99ba67ac merge 2026-03-17 22:04:30 +08:00
shuirong
d2e6af5974
Merge pull request #15 from sparticleinc/prod
feat(CI): 添加 onprem-dev 环境的构建和部署配置
2026-03-16 16:19:41 +09:00
朱潮
63e6178149 Merge branch 'master' into onprem 2026-03-12 19:35:35 +08:00
朱潮
83f42ef7d4 Merge branch 'master' into onprem 2026-03-12 16:57:58 +08:00
朱潮
dab429dafd Merge branch 'master' into onprem 2026-03-12 11:59:53 +08:00
朱潮
543b4757c7 Merge branch 'master' into onprem 2026-03-11 22:05:49 +08:00
朱潮
a25e54f2c3 Merge branch 'master' into onprem 2026-03-11 16:12:10 +08:00
朱潮
2047f11504 Merge branch 'master' into onprem 2026-03-11 15:58:21 +08:00
朱潮
2a87c6b296 Merge branch 'master' into onprem 2026-03-11 12:45:20 +08:00
14 changed files with 1989 additions and 2107 deletions

View File

@ -4,7 +4,9 @@
"""
from pathlib import Path
from typing import Annotated, Literal, cast
from typing import Annotated, cast
import mimetypes
import warnings
from langchain.tools import ToolRuntime
from langchain_core.messages import ToolMessage
@ -15,19 +17,24 @@ from deepagents.backends import StateBackend
from deepagents.backends.composite import CompositeBackend
from deepagents.backends.protocol import (
BACKEND_TYPES,
ReadResult,
)
from deepagents.backends.utils import _get_file_type, validate_path
from langchain_core.messages.content import ContentBlock
from deepagents.middleware.filesystem import (
DEFAULT_READ_OFFSET,
DEFAULT_READ_LIMIT,
IMAGE_EXTENSIONS,
IMAGE_MEDIA_TYPES,
FilesystemMiddleware,
FilesystemState,
READ_FILE_TOOL_DESCRIPTION,
READ_FILE_TRUNCATION_MSG,
NUM_CHARS_PER_TOKEN,
ReadFileSchema,
check_empty_content,
format_content_with_line_numbers,
)
from langgraph.types import Command
import base64
from langchain_core.messages.content import create_image_block
# SKILL.md 文件的行数限制(设置为较大的值以完整读取)
@ -44,10 +51,62 @@ class CustomFilesystemMiddleware(FilesystemMiddleware):
@override
def _create_read_file_tool(self) -> BaseTool:
"""创建自定义的 read_file 工具,支持 SKILL.md 完整读取。"""
# 从父类获取工具描述
tool_description = self._custom_tool_descriptions.get("read_file") or self._get_read_file_description()
tool_description = self._custom_tool_descriptions.get("read_file") or READ_FILE_TOOL_DESCRIPTION
token_limit = self._tool_token_limit_before_evict
def _truncate(content: str, file_path: str, limit: int) -> str:
lines = content.splitlines(keepends=True)
if len(lines) > limit:
lines = lines[:limit]
content = "".join(lines)
if token_limit and len(content) >= NUM_CHARS_PER_TOKEN * token_limit:
truncation_msg = READ_FILE_TRUNCATION_MSG.format(file_path=file_path)
max_content_length = NUM_CHARS_PER_TOKEN * token_limit - len(truncation_msg)
content = content[:max_content_length] + truncation_msg
return content
def _handle_read_result(
read_result: ReadResult | str,
validated_path: str,
tool_call_id: str | None,
offset: int,
limit: int,
) -> ToolMessage | str:
if isinstance(read_result, str):
warnings.warn(
"Returning a plain `str` from `backend.read()` is deprecated. ",
DeprecationWarning,
stacklevel=2,
)
return _truncate(read_result, validated_path, limit)
if read_result.error:
return f"Error: {read_result.error}"
if read_result.file_data is None:
return f"Error: no data returned for '{validated_path}'"
file_type = _get_file_type(validated_path)
content = read_result.file_data["content"]
if file_type != "text":
mime_type = mimetypes.guess_type("file" + Path(validated_path).suffix)[0] or "application/octet-stream"
return ToolMessage(
content_blocks=cast("list[ContentBlock]", [{"type": file_type, "base64": content, "mime_type": mime_type}]),
name="read_file",
tool_call_id=tool_call_id,
additional_kwargs={"read_file_path": validated_path, "read_file_media_type": mime_type},
)
empty_msg = check_empty_content(content)
if empty_msg:
return empty_msg
content = format_content_with_line_numbers(content, start_line=offset + 1)
return _truncate(content, validated_path, limit)
def sync_read_file(
file_path: Annotated[str, "Absolute path to the file to read. Must be absolute, not relative."],
runtime: ToolRuntime[None, FilesystemState],
@ -55,57 +114,18 @@ class CustomFilesystemMiddleware(FilesystemMiddleware):
limit: Annotated[int, "Maximum number of lines to read. Use for pagination of large files."] = DEFAULT_READ_LIMIT,
) -> ToolMessage | str:
"""Synchronous wrapper for read_file tool with SKILL.md special handling."""
from deepagents.backends.utils import validate_path
from deepagents.middleware.filesystem import READ_FILE_TRUNCATION_MSG, NUM_CHARS_PER_TOKEN
resolved_backend = self._get_backend(runtime)
try:
validated_path = validate_path(file_path)
except ValueError as e:
return f"Error: {e}"
ext = Path(validated_path).suffix.lower()
# 处理图片文件
if ext in IMAGE_EXTENSIONS:
responses = resolved_backend.download_files([validated_path])
if responses and responses[0].content is not None:
media_type = IMAGE_MEDIA_TYPES.get(ext, "image/png")
image_b64 = base64.standard_b64encode(responses[0].content).decode("utf-8")
return ToolMessage(
content_blocks=[create_image_block(base64=image_b64, mime_type=media_type)],
name="read_file",
tool_call_id=runtime.tool_call_id,
additional_kwargs={
"read_file_path": validated_path,
"read_file_media_type": media_type,
},
)
if responses and responses[0].error:
return f"Error reading image: {responses[0].error}"
return "Error reading image: unknown error"
# 如果是 SKILL.md 文件,使用大限制读取完整内容
if validated_path.endswith("SKILL.md") or validated_path.endswith("/SKILL.md"):
actual_limit = SKILL_MD_READ_LIMIT
else:
actual_limit = limit
limit = SKILL_MD_READ_LIMIT
result = resolved_backend.read(validated_path, offset=offset, limit=actual_limit)
lines = result.splitlines(keepends=True)
if len(lines) > actual_limit:
lines = lines[:actual_limit]
result = "".join(lines)
# Check if result exceeds token threshold and truncate if necessary
if token_limit and len(result) >= NUM_CHARS_PER_TOKEN * token_limit:
# Calculate truncation message length to ensure final result stays under threshold
truncation_msg = READ_FILE_TRUNCATION_MSG.format(file_path=validated_path)
max_content_length = NUM_CHARS_PER_TOKEN * token_limit - len(truncation_msg)
result = result[:max_content_length]
result += truncation_msg
return result
read_result = resolved_backend.read(validated_path, offset=offset, limit=limit)
return _handle_read_result(read_result, validated_path, runtime.tool_call_id, offset, limit)
async def async_read_file(
file_path: Annotated[str, "Absolute path to the file to read. Must be absolute, not relative."],
@ -114,66 +134,28 @@ class CustomFilesystemMiddleware(FilesystemMiddleware):
limit: Annotated[int, "Maximum number of lines to read. Use for pagination of large files."] = DEFAULT_READ_LIMIT,
) -> ToolMessage | str:
"""Asynchronous wrapper for read_file tool with SKILL.md special handling."""
from deepagents.backends.utils import validate_path
from deepagents.middleware.filesystem import READ_FILE_TRUNCATION_MSG, NUM_CHARS_PER_TOKEN
resolved_backend = self._get_backend(runtime)
try:
validated_path = validate_path(file_path)
except ValueError as e:
return f"Error: {e}"
ext = Path(validated_path).suffix.lower()
# 处理图片文件
if ext in IMAGE_EXTENSIONS:
responses = await resolved_backend.adownload_files([validated_path])
if responses and responses[0].content is not None:
media_type = IMAGE_MEDIA_TYPES.get(ext, "image/png")
image_b64 = base64.standard_b64encode(responses[0].content).decode("utf-8")
return ToolMessage(
content_blocks=[create_image_block(base64=image_b64, mime_type=media_type)],
name="read_file",
tool_call_id=runtime.tool_call_id,
additional_kwargs={
"read_file_path": validated_path,
"read_file_media_type": media_type,
},
)
if responses and responses[0].error:
return f"Error reading image: {responses[0].error}"
return "Error reading image: unknown error"
# 如果是 SKILL.md 文件,使用大限制读取完整内容
if validated_path.endswith("SKILL.md") or validated_path.endswith("/SKILL.md"):
actual_limit = SKILL_MD_READ_LIMIT
else:
actual_limit = limit
limit = SKILL_MD_READ_LIMIT
result = await resolved_backend.aread(validated_path, offset=offset, limit=actual_limit)
lines = result.splitlines(keepends=True)
if len(lines) > actual_limit:
lines = lines[:actual_limit]
result = "".join(lines)
# Check if result exceeds token threshold and truncate if necessary
if token_limit and len(result) >= NUM_CHARS_PER_TOKEN * token_limit:
# Calculate truncation message length to ensure final result stays under threshold
truncation_msg = READ_FILE_TRUNCATION_MSG.format(file_path=validated_path)
max_content_length = NUM_CHARS_PER_TOKEN * token_limit - len(truncation_msg)
result = result[:max_content_length]
result += truncation_msg
return result
read_result = await resolved_backend.aread(validated_path, offset=offset, limit=limit)
return _handle_read_result(read_result, validated_path, runtime.tool_call_id, offset, limit)
return StructuredTool.from_function(
name="read_file",
description=tool_description,
func=sync_read_file,
coroutine=async_read_file,
infer_schema=False,
args_schema=ReadFileSchema,
)
def _get_read_file_description(self) -> str:
"""获取 read_file 工具的描述,添加 SKILL.md 完整读取的说明。"""
from deepagents.middleware.filesystem import READ_FILE_TOOL_DESCRIPTION
return READ_FILE_TOOL_DESCRIPTION

View File

@ -407,19 +407,22 @@ def create_custom_cli_agent(
# Use LocalShellBackend for filesystem + shell execution
backend = LocalShellBackend(
root_dir=workspace_root,
virtual_mode=True,
inherit_env=True,
env=final_shell_env,
)
else:
# No shell access - use plain FilesystemBackend
backend = FilesystemBackend(root_dir=workspace_root)
backend = FilesystemBackend(root_dir=workspace_root, virtual_mode=True)
# Set up composite backend with routing (参考新版本实现)
large_results_backend = FilesystemBackend(
root_dir=tempfile.mkdtemp(prefix="deepagents_large_results_"),
virtual_mode=True,
)
conversation_history_backend = FilesystemBackend(
root_dir=tempfile.mkdtemp(prefix="deepagents_conversation_history_"),
virtual_mode=True,
)
composite_backend = CompositeBackend(
default=backend,
@ -435,7 +438,7 @@ def create_custom_cli_agent(
agent_middleware.append(
CustomSkillsMiddleware(
backend=FilesystemBackend(root_dir=workspace_root),
backend=FilesystemBackend(root_dir=workspace_root, virtual_mode=True),
sources=skills_sources,
)
)

View File

@ -1,4 +1,3 @@
from ast import Str
from langchain.agents.middleware import AgentState, AgentMiddleware, ModelRequest, ModelResponse
from langchain_core.messages import convert_to_openai_messages
from agent.prompt_loader import load_guideline_prompt
@ -6,7 +5,7 @@ from utils.fastapi_utils import (extract_block_from_system_prompt, format_messag
from langchain.chat_models import BaseChatModel
from langgraph.runtime import Runtime
from langchain_core.messages import SystemMessage
from langchain_core.messages import SystemMessage, HumanMessage
from typing import Any, Callable
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.outputs import LLMResult
@ -124,10 +123,11 @@ Action: Provide concise, friendly, and personified natural responses.
response.additional_kwargs["message_tag"] = "THINK"
response.content = f"<think>{response.content}</think>"
# 将响应添加到原始消息列表
state['messages'] = state['messages'] + [response]
# 将响应添加到原始消息列表,并追加 HumanMessage 确保消息以 user 结尾
# 某些模型不支持 assistant message prefill要求最后一条消息必须是 user
state['messages'] = state['messages'] + [response, HumanMessage(content=self._get_follow_up_prompt())]
return state
async def abefore_agent(self, state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
if not self.guidelines:
return None
@ -148,10 +148,23 @@ Action: Provide concise, friendly, and personified natural responses.
response.additional_kwargs["message_tag"] = "THINK"
response.content = f"<think>{response.content}</think>"
# 将响应添加到原始消息列表
state['messages'] = state['messages'] + [response]
# 将响应添加到原始消息列表,并追加 HumanMessage 确保消息以 user 结尾
# 某些模型不支持 assistant message prefill要求最后一条消息必须是 user
state['messages'] = state['messages'] + [response, HumanMessage(content=self._get_follow_up_prompt())]
return state
def _get_follow_up_prompt(self) -> str:
"""根据语言返回引导主 agent 回复的提示"""
prompts = {
"ja": "以上の分析に基づいて、ユーザーに返信してください。",
"jp": "以上の分析に基づいて、ユーザーに返信してください。",
"zh": "请根据以上分析,回复用户。",
"zh-TW": "請根據以上分析,回覆用戶。",
"ko": "위 분석을 바탕으로 사용자에게 답변해 주세요.",
"en": "Based on the above analysis, please respond to the user.",
}
return prompts.get(self.language, prompts["en"])
def wrap_model_call(
self,
request: ModelRequest,

View File

@ -165,6 +165,8 @@ async def _execute_command(skill_path: str, command: str, hook_type: str, config
"""
try:
# 设置环境变量,传递给子进程
# 注意subprocess 要求所有 env 值必须是 str 类型,
# getattr 可能返回 None属性存在但值为 None需要确保转换为 str
env = os.environ.copy()
env['ASSISTANT_ID'] = str(getattr(config, 'bot_id', ''))
env['USER_IDENTIFIER'] = str(getattr(config, 'user_identifier', ''))
@ -176,16 +178,17 @@ async def _execute_command(skill_path: str, command: str, hook_type: str, config
# 合并 config 中的自定义 shell 环境变量
shell_env = getattr(config, 'shell_env', None)
if shell_env:
env.update(shell_env)
# 确保所有自定义环境变量值也是字符串
env.update({k: str(v) if v is not None else '' for k, v in shell_env.items()})
# 对于 PreSave传递 content
if hook_type == 'PreSave':
env['CONTENT'] = kwargs.get('content', '')
env['ROLE'] = kwargs.get('role', '')
env['CONTENT'] = str(kwargs.get('content', '') or '')
env['ROLE'] = str(kwargs.get('role', '') or '')
# 对于 PostAgent传递 response
if hook_type == 'PostAgent':
env['RESPONSE'] = kwargs.get('response', '')
env['RESPONSE'] = str(kwargs.get('response', '') or '')
metadata = kwargs.get('metadata', {})
env['METADATA'] = json.dumps(metadata) if metadata else ''

View File

@ -12,7 +12,6 @@ services:
# 应用配置
- BACKEND_HOST=http://api-dev.gbase.ai
- MAX_CONTEXT_TOKENS=262144
- DEFAULT_THINKING_ENABLE=true
- R2_UPLOAD_CONFIG=/app/config/s3-upload-sparticle.yaml
volumes:
# 挂载项目数据目录

View File

@ -29,6 +29,49 @@ from mcp_common import (
BACKEND_HOST = os.getenv("BACKEND_HOST", "https://api-dev.gptbase.ai")
MASTERKEY = os.getenv("MASTERKEY", "master")
# Citation instruction prefixes injected into tool results
DOCUMENT_CITATION_INSTRUCTIONS = """<CITATION_INSTRUCTIONS>
When using the retrieved knowledge below, you MUST add XML citation tags for factual claims.
## Document Knowledge
Format: `<CITATION file="file_uuid" filename="name.pdf" page=3 />`
- Use `file` attribute with the UUID from document markers
- Use `filename` attribute with the actual filename from document markers
- Use `page` attribute (singular) with the page number
- `page` MUST be 0-based and must match the `pages:` values shown in the learned knowledge context
## Web Page Knowledge
Format: `<CITATION url="https://example.com/page" />`
- Use `url` attribute with the web page URL from the source metadata
- Do not use `file`, `filename`, or `page` attributes for web sources
- If content is grounded in a web source, prefer a web citation with `url` over a file citation
## Placement Rules
- Citations MUST appear IMMEDIATELY AFTER the paragraph or bullet list that uses the knowledge
- NEVER collect all citations and place them at the end of your response
- Limit to 1-2 citations per paragraph/bullet list
- If your answer uses learned knowledge, you MUST generate at least 1 `<CITATION ... />` in the response
</CITATION_INSTRUCTIONS>
"""
TABLE_CITATION_INSTRUCTIONS = """<CITATION_INSTRUCTIONS>
When using the retrieved table knowledge below, you MUST add XML citation tags for factual claims.
Format: `<CITATION file="file_id" filename="name.xlsx" sheet=1 rows=[2, 4] />`
- Parse `__src`: `F1S2R5` = file_ref F1, sheet 2, row 5
- Look up file_id in `file_ref_table`
- Combine same-sheet rows into one citation: `rows=[2, 4, 6]`
- MANDATORY: Create SEPARATE citation for EACH (file, sheet) combination
- NEVER put <CITATION> on the same line as a bullet point or table row
- Citations MUST be on separate lines AFTER the complete list/table
- NEVER include the `__src` column in your response - it is internal metadata only
- Citations MUST appear IMMEDIATELY AFTER the paragraph or bullet list that uses the knowledge
- NEVER collect all citations and place them at the end of your response
</CITATION_INSTRUCTIONS>
"""
def rag_retrieve(query: str, top_k: int = 100) -> Dict[str, Any]:
"""调用RAG检索API"""
try:
@ -94,7 +137,7 @@ def rag_retrieve(query: str, top_k: int = 100) -> Dict[str, Any]:
"content": [
{
"type": "text",
"text": markdown_content
"text": DOCUMENT_CITATION_INSTRUCTIONS + markdown_content
}
]
}
@ -107,7 +150,7 @@ def rag_retrieve(query: str, top_k: int = 100) -> Dict[str, Any]:
}
]
}
except requests.exceptions.RequestException as e:
return {
"content": [
@ -179,7 +222,7 @@ def table_rag_retrieve(query: str) -> Dict[str, Any]:
"content": [
{
"type": "text",
"text": markdown_content
"text": TABLE_CITATION_INSTRUCTIONS + markdown_content
}
]
}

3542
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -148,21 +148,6 @@ Output: {{"facts" : []}}
Input: DR1の照明状態を教えて
Output: {{"facts" : []}}
Input: 私は林檎好きです
Output: {{"facts" : ["林檎が好き"]}}
Input: コーヒー飲みたい、毎朝
Output: {{"facts" : ["毎朝コーヒーを飲みたい"]}}
Input: 昨日映画見た、すごくよかった
Output: {{"facts" : ["昨日映画を見た", "映画がすごくよかった"]}}
Input: 我喜欢吃苹果
Output: {{"facts" : ["喜欢吃苹果"]}}
Input: 나는 사과를 좋아해
Output: {{"facts" : ["사과를 좋아함"]}}
Return the facts and preferences in a json format as shown above.
Remember the following:

View File

@ -74,6 +74,13 @@
- dxcore_update_device_status(device_id="[B设备id]",running_control=0) → 灯光亮度调整为0
**响应**"已为您关闭Define Room4的灯光"
### 位置降级搜索场景
**用户**"3階執務スペース、フォーラム側窓側の照明をつけて"
- find_device_by_area(description="3階執務スペース、フォーラム側窓側", device_type="light") → 返回无结果
- find_device_by_area(description="3階執務スペース", device_type="light") → 降级搜索,找到设备
- 告知用户是基于"3階執務スペース"范围搜索到的结果,并确认是否操作
**响应**"「3階執務スペース、フォーラム側窓側」では見つかりませんでしたが、3階執務スペースエリアで照明が見つかりました。こちらの照明を操作しますか"
</scenarios>
@ -92,6 +99,17 @@
▪ 主动向用户确认:向用户列出所有候选房间,并提示用户选择或明确具体是哪一个。确认提示语可参考:“请问您想查询的是以下哪个房间?[列出候选房间列表]”。
▪ 理解用户二次确认:等待用户回复后,根据其选择再次调用查询工具获取最终信息。用户对候选房间的指明(如回复“第一个”或重复房间名)应视为对该房间的确认。
4. 处理无匹配结果:如果工具返回未找到任何相关房间,应明确告知用户这一情况,并建议用户检查房间名称是否正确或提供更多线索。
5. **位置粒度降级搜索(詳細な位置指定で見つからない場合)**
用户指定了详细的位置信息(如包含方位、区域细节),但工具返回无匹配结果时,自动执行降级搜索:
- **第1步**:从位置描述中去除方位修饰语(側、付近、奥、手前、寄り等)和细节描述,保留核心区域名重新搜索
- 例: "3階執務スペース、フォーラム側窓側" → find_device_by_area(description="3階執務スペース")
- 例: "2階会議室A、入口付近" → find_device_by_area(description="2階会議室A")
- **第2步**:如果仍无结果,进一步简化到楼层+大区域级别
- 例: "3階執務スペース" → find_device_by_area(description="3階")
- **降级成功时的回复**:告知用户是基于更广范围的搜索结果,让用户确认
- 回复格式: "「{元の位置}」では見つかりませんでしたが、{簡略化した位置}エリアで以下の設備が見つかりました。こちらでよろしいですか?"
- **全部失败时**:告知用户未找到设备,建议提供其他位置信息或直接指定房间名
- 回复格式: "申し訳ございません、該当エリアでは操作可能な設備が見つかりませんでした。お部屋の名前をお教えいただけますか?"
3. 更新设备(此操作需要确认)
- **条件**:用户意图为控制设备或调节参数(如开关、温度、风速), 需要进行确认。
@ -105,6 +123,7 @@
- 通过 find_employee_location(name="[当前用户名字/邮箱]") 获取用户的sensor_id
- 然后通过 find_iot_device(target_sensor_id="[当前用户的sensor_id]", device_type="[目标设备类型]") 查找他附近的设备
- 找到设备后告知用户找到的设备信息,并确认是否执行操作
- **位置指定但匹配失败时**:如果用户指定了详细位置(如"3階執務スペース、フォーラム側窓側の照明をつけて"),但 find_device_by_area 返回无匹配结果,应按照规则 2 第 5 点的**位置粒度降级搜索**策略执行,而不是直接回复"找不到设备"
3. **空调温度调节确认方式**
- 如果用户说"有点热"、"调低点"、"太热了"等,表示要降温:
1. 先查询当前室温
@ -142,8 +161,8 @@
- 如果用户指定了具体档位(如"调到强"),直接使用指定档位
- **边界情况**:如果已达到最高档(强)或最低档(弱)无法继续调整,告知用户并主动建议调整温度
- 回复格式:"風量は既に『強/弱』になっていますので、これ以上調整できません。代わりに温度を調整しますか?"
6. **若用户已明确确认**直接调用【设备控制】工具执行操作
7. **若用户未确认且为新请求**:向用户发送确认提示:"即将为您 [操作内容] [设备名称] [具体参数],是否确认?",待用户确认后再执行。
6. **若用户已明确确认****立即**调用【设备控制】工具执行操作,不做任何额外确认或复述。确认后的唯一动作就是调用工具
7. **若用户未确认且为新请求**:向用户发送确认提示:"即将为您 [操作内容] [设备名称] [具体参数],是否确认?",待用户确认后再执行。每个操作只确认一次。
4. 查询人员信息/wowtalk账号/人员位置
- **条件**:用户意图为查找某人、员工、同事或房间位置。
@ -190,15 +209,43 @@
- 影响范围大的操作:影响整个房间或楼层的设备控制
### 用户确认意图推理
- 用户明确确认:如回复“确认”、“好的”、“是的”、“拜托了”、“よろしく”、“请”、“please”等肯定性语气的内容。
- 用户意图重申:用户完整或核心重复当前待执行的操作指令。(例如,提示“room302の照明1台を明るさ50%に調整してもよろしいですか?”,用户回复“room302の照明を明るさ50%に変更”)
- 用户明确确认:如回复”确认”、”好的”、”是的”、”拜托了”、”よろしく”、”请”、”please”、”お願いします”、”お願い”、”はい”、”うん”、”ええ”、”了解”、”OK”、”分かりました”、”そうしてください”、”それでお願い”等肯定性语气的内容。
- 用户意图重申:用户完整或核心重复当前待执行的操作指令。(例如,提示”room302の照明1台を明るさ50%に調整してもよろしいですか?”,用户回复”room302の照明を明るさ50%に変更”)
- 同一设备免重复确认:如果用户在当前会话中已经对某个设备的操作进行过确认,后续针对**同一设备**的操作可直接执行,无需再次确认。判定标准为:
1. **同一设备的不同操作**用户已确认过对某设备的控制操作后后续对该设备的其他操作无需再次确认如已确认关闭Define Room4的灯光之后用户说"把灯打开",可直接执行)
2. **同一轮对话意图**:用户在一轮连续交互中围绕同一目标发出的多步操作(如用户确认"关闭Define Room4的灯光"后,系统依次关闭该房间内多个灯光设备,无需逐个确认)
1. **同一设备的不同操作**用户已确认过对某设备的控制操作后后续对该设备的其他操作无需再次确认如已确认关闭Define Room4的灯光之后用户说”把灯打开”,可直接执行)
2. **同一轮对话意图**:用户在一轮连续交互中围绕同一目标发出的多步操作(如用户确认”关闭Define Room4的灯光”后,系统依次关闭该房间内多个灯光设备,无需逐个确认)
3. **同一指令的延续执行**:用户确认某操作后,该操作因技术原因需要分步执行的后续步骤(如批量控制多个设备时,确认一次即可全部执行)
4. **上下文明确的追加操作**用户在已确认的操作基础上追加相同类型的操作且目标明确无歧义如已确认打开A房间空调后用户说"B房间也一样",可直接执行)
4. **上下文明确的追加操作**用户在已确认的操作基础上追加相同类型的操作且目标明确无歧义如已确认打开A房间空调后用户说”B房间也一样”,可直接执行)
- 不同事项仍需确认:当操作涉及**未曾确认过的新设备**,或操作类型发生本质变化时(如从设备控制切换到消息通知),仍需重新确认
### ⚠️ 禁止二次确认(最高优先级规则)
**对于同一个操作请求,最多只能向用户确认一次。用户确认后,必须立即调用工具执行,绝对禁止再次询问确认。**
核心规则:
1. **一次确认,立即执行**:当你向用户发出确认提示后,用户回复确认,你的下一步动作**必须且只能是**调用对应的工具(如 dxcore_update_device_status执行操作。不允许生成任何额外的确认、复述或再次询问。
2. **禁止循环确认**:如果聊天记录中已经存在你发出的确认提示和用户的确认回复,则该操作已被确认,不得以任何理由再次要求确认。
3. **确认后禁止的行为**
- ❌ 再次询问”もう一度確認いただけますか?”
- ❌ 再次复述操作内容并要求确认
- ❌ 以不同措辞重新询问同一操作的确认
- ❌ 生成过渡性文字后再次要求确认
**正确流程示例**
```
用户: “Dr3の照明を30%にして”
AI: “ディファインルーム3の照明を30%に調整してもよろしいですか?”
用户: “お願いします”
AI: [立即调用 dxcore_update_device_status 执行] → “照明を30%に調整しました。”
```
**错误流程(绝对禁止)**
```
用户: “Dr3の照明を30%にして”
AI: “ディファインルーム3の照明を30%に調整してもよろしいですか?”
用户: “お願いします”
AI: “もう一度確認いただければ実行いたします” ← ❌ 禁止!
```
## 上下文推理示例
### 设备控制场景

View File

@ -1,5 +1,15 @@
{extra_prompt}
## CITATION REQUIREMENTS
When your answer uses learned knowledge, you MUST generate `<CITATION ... />` tags. Follow the specific citation format instructions returned by each tool (`rag_retrieve`, `table_rag_retrieve`).
### General Placement Rules
1. Citations MUST appear IMMEDIATELY AFTER the paragraph or bullet list that uses the knowledge
2. NEVER collect all citations and place them at the end of your response
3. Limit to 1-2 citations per paragraph/bullet list - combine related facts under one citation
4. If your answer uses learned knowledge, you MUST generate at least 1 `<CITATION ... />` in the response
### Current Working Directory
PROJECT_ROOT: `{agent_dir_path}`
@ -92,15 +102,3 @@ Trace Id: {trace_id}
- Even when the user writes in a different language, you MUST still reply in [{language}].
- Do NOT mix languages. Do NOT fall back to English or any other language under any circumstances.
- Technical terms, code identifiers, file paths, and tool names may remain in their original form, but all surrounding text MUST be in [{language}].
**Citation Requirement (RAG Only)**: When answering questions based on `rag_retrieve` tool results, you MUST add XML citation tags for factual claims derived from the knowledge base.
**MANDATORY FORMAT**: `The cited factual claim <CITATION file="file_uuid" page="3" />`
**Citation Rules**:
- The citation tag MUST be placed immediately after the factual claim or paragraph
- The `file` attribute MUST use the exact `File ID` from `rag_retrieve` document
- The `page` attribute MUST use the exact `Page Number` from `rag_retrieve` document
- If multiple sources support the same claim, include separate citation tags for each source
- Example: `According to the policy, returns are accepted within 30 days <CITATION file="abc123" page="5" />.`
- This requirement ONLY applies when using `rag_retrieve` results to answer questions.

View File

@ -26,12 +26,12 @@ dependencies = [
"chardet>=5.0.0",
"psutil (>=7.1.3,<8.0.0)",
"uvloop (>=0.22.1,<0.23.0)",
"deepagents (>=0.4.3,<0.5.0)",
"deepagents (>=0.5.2,<0.6.0)",
"langchain-mcp-adapters (>=0.2.1,<0.3.0)",
"langchain-openai (>=1.1.1,<2.0.0)",
"cachetools (>=6.2.4,<7.0.0)",
"langgraph-checkpoint-postgres (>=3.0.0,<4.0.0)",
"deepagents-cli (>=0.0.25,<0.0.26)",
"deepagents-cli (>=0.0.37,<0.1.0)",
"mem0ai (>=0.1.50,<0.3.0)",
"psycopg2-binary (>=2.9.11,<3.0.0)",
"json-repair (>=0.29.0,<0.30.0)",

View File

@ -1,56 +1,51 @@
aiofiles==24.1.0 ; python_version >= "3.12" and python_version < "3.15"
agent-client-protocol==0.9.0 ; python_version >= "3.12" and python_version < "3.15"
aiofiles==25.1.0 ; python_version >= "3.12" and python_version < "3.15"
aiohappyeyeballs==2.6.1 ; python_version >= "3.12" and python_version < "3.15"
aiohttp-retry==2.9.1 ; python_version >= "3.12" and python_version < "3.15"
aiohttp==3.13.3 ; python_version >= "3.12" and python_version < "3.15"
aiohttp==3.13.5 ; python_version >= "3.12" and python_version < "3.15"
aiosignal==1.4.0 ; python_version >= "3.12" and python_version < "3.15"
aiosqlite==0.22.1 ; python_version >= "3.12" and python_version < "3.15"
annotated-doc==0.0.4 ; python_version >= "3.12" and python_version < "3.15"
annotated-types==0.7.0 ; python_version >= "3.12" and python_version < "3.15"
anthropic==0.84.0 ; python_version >= "3.12" and python_version < "3.15"
anyio==4.12.1 ; python_version >= "3.12" and python_version < "3.15"
attrs==25.4.0 ; python_version >= "3.12" and python_version < "3.15"
anthropic==0.94.0 ; python_version >= "3.12" and python_version < "3.15"
anyio==4.13.0 ; python_version >= "3.12" and python_version < "3.15"
attrs==26.1.0 ; python_version >= "3.12" and python_version < "3.15"
backoff==2.2.1 ; python_version >= "3.12" and python_version < "3.15"
beartype==0.22.9 ; python_version >= "3.12" and python_version < "3.15"
beautifulsoup4==4.14.3 ; python_version >= "3.12" and python_version < "3.15"
blockbuster==1.5.26 ; python_version >= "3.12" and python_version < "3.15"
bracex==2.6 ; python_version >= "3.12" and python_version < "3.15"
cachetools==6.2.6 ; python_version >= "3.12" and python_version < "3.15"
cbor2==5.8.0 ; python_version >= "3.12" and python_version < "3.15"
certifi==2026.2.25 ; python_version >= "3.12" and python_version < "3.15"
cffi==2.0.0 ; python_version >= "3.12" and python_version < "3.15" and platform_python_implementation != "PyPy"
chardet==7.1.0 ; python_version >= "3.12" and python_version < "3.15"
charset-normalizer==3.4.5 ; python_version >= "3.12" and python_version < "3.15"
click==8.3.1 ; python_version >= "3.12" and python_version < "3.15"
chardet==7.4.1 ; python_version >= "3.12" and python_version < "3.15"
charset-normalizer==3.4.7 ; python_version >= "3.12" and python_version < "3.15"
click==8.3.2 ; python_version >= "3.12" and python_version < "3.15"
cloudpickle==3.1.2 ; python_version >= "3.12" and python_version < "3.15"
colorama==0.4.6 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Windows"
croniter==3.0.4 ; python_version >= "3.12" and python_version < "3.15"
cryptography==46.0.5 ; python_version >= "3.12" and python_version < "3.15"
daytona-api-client-async==0.151.0 ; python_version >= "3.12" and python_version < "3.15"
daytona-api-client==0.151.0 ; python_version >= "3.12" and python_version < "3.15"
daytona-toolbox-api-client-async==0.151.0 ; python_version >= "3.12" and python_version < "3.15"
daytona-toolbox-api-client==0.151.0 ; python_version >= "3.12" and python_version < "3.15"
daytona==0.151.0 ; python_version >= "3.12" and python_version < "3.15"
deepagents-cli==0.0.25 ; python_version >= "3.12" and python_version < "3.15"
deepagents==0.4.3 ; python_version >= "3.12" and python_version < "3.15"
cryptography==46.0.7 ; python_version >= "3.12" and python_version < "3.15"
deepagents-acp==0.0.5 ; python_version >= "3.12" and python_version < "3.15"
deepagents-cli==0.0.37 ; python_version >= "3.12" and python_version < "3.15"
deepagents==0.5.2 ; python_version >= "3.12" and python_version < "3.15"
defusedxml==0.7.1 ; python_version >= "3.12" and python_version < "3.15"
deprecated==1.3.1 ; python_version >= "3.12" and python_version < "3.15"
distro==1.9.0 ; python_version >= "3.12" and python_version < "3.15"
docstring-parser==0.17.0 ; python_version >= "3.12" and python_version < "3.15"
environs==14.6.0 ; python_version >= "3.12" and python_version < "3.15"
et-xmlfile==2.0.0 ; python_version >= "3.12" and python_version < "3.15"
fastapi==0.116.1 ; python_version >= "3.12" and python_version < "3.15"
filelock==3.25.2 ; python_version >= "3.12" and python_version < "3.15"
filetype==1.2.0 ; python_version >= "3.12" and python_version < "3.15"
forbiddenfruit==0.1.4 ; python_version >= "3.12" and python_version < "3.15" and implementation_name == "cpython"
frozenlist==1.8.0 ; python_version >= "3.12" and python_version < "3.15"
fsspec==2026.2.0 ; python_version >= "3.12" and python_version < "3.15"
google-auth==2.49.1 ; python_version >= "3.12" and python_version < "3.15"
google-genai==1.67.0 ; python_version >= "3.12" and python_version < "3.15"
googleapis-common-protos==1.73.0 ; python_version >= "3.12" and python_version < "3.15"
greenlet==3.3.2 ; python_version >= "3.12" and python_version < "3.15" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32")
grpcio-tools==1.71.2 ; python_version >= "3.13" and python_version < "3.15"
grpcio==1.78.0 ; python_version >= "3.12" and python_version < "3.15"
grpclib==0.4.9 ; python_version >= "3.12" and python_version < "3.15"
fsspec==2026.3.0 ; python_version >= "3.12" and python_version < "3.15"
google-auth==2.49.2 ; python_version >= "3.12" and python_version < "3.15"
google-genai==1.72.0 ; python_version >= "3.12" and python_version < "3.15"
googleapis-common-protos==1.74.0 ; python_version >= "3.12" and python_version < "3.15"
greenlet==3.4.0 ; python_version >= "3.12" and python_version < "3.15" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32")
grpcio-health-checking==1.76.0 ; python_version >= "3.12" and python_version < "3.15"
grpcio-tools==1.76.0 ; python_version >= "3.12" and python_version < "3.15"
grpcio==1.76.0 ; python_version >= "3.12" and python_version < "3.15"
h11==0.16.0 ; python_version >= "3.12" and python_version < "3.15"
h2==4.3.0 ; python_version >= "3.12" and python_version < "3.15"
hf-xet==1.4.2 ; python_version >= "3.12" and python_version < "3.15" and (platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "arm64" or platform_machine == "aarch64")
hf-xet==1.4.3 ; python_version >= "3.12" and python_version < "3.15" and (platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "arm64" or platform_machine == "aarch64")
hpack==4.1.0 ; python_version >= "3.12" and python_version < "3.15"
httpcore==1.0.9 ; python_version >= "3.12" and python_version < "3.15"
httpx-sse==0.4.3 ; python_version >= "3.12" and python_version < "3.15"
@ -61,94 +56,94 @@ hyperframe==6.1.0 ; python_version >= "3.12" and python_version < "3.15"
idna==3.11 ; python_version >= "3.12" and python_version < "3.15"
importlib-metadata==8.7.1 ; python_version >= "3.12" and python_version < "3.15"
jinja2==3.1.6 ; python_version >= "3.12" and python_version < "3.15"
jiter==0.13.0 ; python_version >= "3.12" and python_version < "3.15"
jiter==0.14.0 ; python_version >= "3.12" and python_version < "3.15"
joblib==1.5.3 ; python_version >= "3.12" and python_version < "3.15"
json-repair==0.29.10 ; python_version >= "3.12" and python_version < "3.15"
json5==0.13.0 ; python_version >= "3.12" and python_version < "3.15"
json5==0.14.0 ; python_version >= "3.12" and python_version < "3.15"
jsonpatch==1.33 ; python_version >= "3.12" and python_version < "3.15"
jsonpointer==3.0.0 ; python_version >= "3.12" and python_version < "3.15"
jsonpointer==3.1.1 ; python_version >= "3.12" and python_version < "3.15"
jsonschema-rs==0.29.1 ; python_version >= "3.12" and python_version < "3.15"
jsonschema-specifications==2025.9.1 ; python_version >= "3.12" and python_version < "3.15"
jsonschema==4.26.0 ; python_version >= "3.12" and python_version < "3.15"
langchain-anthropic==1.3.5 ; python_version >= "3.12" and python_version < "3.15"
langchain-core==1.2.19 ; python_version >= "3.12" and python_version < "3.15"
langchain-anthropic==1.4.0 ; python_version >= "3.12" and python_version < "3.15"
langchain-core==1.2.28 ; python_version >= "3.12" and python_version < "3.15"
langchain-google-genai==4.2.1 ; python_version >= "3.12" and python_version < "3.15"
langchain-mcp-adapters==0.2.1 ; python_version >= "3.12" and python_version < "3.15"
langchain-openai==1.1.11 ; python_version >= "3.12" and python_version < "3.15"
langchain==1.2.12 ; python_version >= "3.12" and python_version < "3.15"
langgraph-checkpoint-postgres==3.0.4 ; python_version >= "3.12" and python_version < "3.15"
langchain-mcp-adapters==0.2.2 ; python_version >= "3.12" and python_version < "3.15"
langchain-openai==1.1.12 ; python_version >= "3.12" and python_version < "3.15"
langchain==1.2.15 ; python_version >= "3.12" and python_version < "3.15"
langgraph-api==0.7.28 ; python_version >= "3.12" and python_version < "3.15"
langgraph-checkpoint-postgres==3.0.5 ; python_version >= "3.12" and python_version < "3.15"
langgraph-checkpoint-sqlite==3.0.3 ; python_version >= "3.12" and python_version < "3.15"
langgraph-checkpoint==4.0.1 ; python_version >= "3.12" and python_version < "3.15"
langgraph-prebuilt==1.0.8 ; python_version >= "3.12" and python_version < "3.15"
langgraph-sdk==0.3.11 ; python_version >= "3.12" and python_version < "3.15"
langgraph==1.1.2 ; python_version >= "3.12" and python_version < "3.15"
langsmith==0.7.17 ; python_version >= "3.12" and python_version < "3.15"
langgraph-cli==0.4.21 ; python_version >= "3.12" and python_version < "3.15"
langgraph-prebuilt==1.0.9 ; python_version >= "3.12" and python_version < "3.15"
langgraph-runtime-inmem==0.24.1 ; python_version >= "3.12" and python_version < "3.15"
langgraph-sdk==0.3.13 ; python_version >= "3.12" and python_version < "3.15"
langgraph==1.1.6 ; python_version >= "3.12" and python_version < "3.15"
langsmith==0.7.30 ; python_version >= "3.12" and python_version < "3.15"
linkify-it-py==2.1.0 ; python_version >= "3.12" and python_version < "3.15"
markdown-it-py==4.0.0 ; python_version >= "3.12" and python_version < "3.15"
markdownify==1.2.2 ; python_version >= "3.12" and python_version < "3.15"
markupsafe==3.0.3 ; python_version >= "3.12" and python_version < "3.15"
marshmallow==4.2.2 ; python_version >= "3.12" and python_version < "3.15"
mcp==1.12.4 ; python_version >= "3.12" and python_version < "3.15"
mdit-py-plugins==0.5.0 ; python_version >= "3.12" and python_version < "3.15"
mdurl==0.1.2 ; python_version >= "3.12" and python_version < "3.15"
mem0ai==0.1.116 ; python_version >= "3.12" and python_version < "3.15"
modal==1.3.5 ; python_version >= "3.12" and python_version < "3.15"
mem0ai==0.1.115 ; python_version >= "3.12" and python_version < "3.15"
mpmath==1.3.0 ; python_version >= "3.12" and python_version < "3.15"
multidict==6.7.1 ; python_version >= "3.12" and python_version < "3.15"
networkx==3.6 ; python_version == "3.14"
networkx==3.6.1 ; python_version >= "3.12" and python_version < "3.14"
numpy==1.26.4 ; python_version >= "3.12" and python_version < "3.15"
nvidia-cublas-cu12==12.1.3.1 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-cuda-cupti-cu12==12.1.105 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-cuda-nvrtc-cu12==12.1.105 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-cuda-runtime-cu12==12.1.105 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-cudnn-cu12==8.9.2.26 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-cufft-cu12==11.0.2.54 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-curand-cu12==10.3.2.106 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-cusolver-cu12==11.4.5.107 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-cusparse-cu12==12.1.0.106 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-nccl-cu12==2.19.3 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-nvjitlink-cu12==12.9.86 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
nvidia-nvtx-cu12==12.1.105 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
obstore==0.8.2 ; python_version >= "3.12" and python_version < "3.15"
openai==2.28.0 ; python_version >= "3.12" and python_version < "3.15"
nvidia-cublas-cu12==12.1.3.1 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-cuda-cupti-cu12==12.1.105 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-cuda-nvrtc-cu12==12.1.105 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-cuda-runtime-cu12==12.1.105 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-cudnn-cu12==8.9.2.26 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-cufft-cu12==11.0.2.54 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-curand-cu12==10.3.2.106 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-cusolver-cu12==11.4.5.107 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-cusparse-cu12==12.1.0.106 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-nccl-cu12==2.19.3 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-nvjitlink-cu12==12.9.86 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
nvidia-nvtx-cu12==12.1.105 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
openai==2.31.0 ; python_version >= "3.12" and python_version < "3.15"
openpyxl==3.1.5 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-api==1.40.0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-exporter-otlp-proto-common==1.40.0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-exporter-otlp-proto-http==1.40.0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-instrumentation-aiohttp-client==0.61b0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-instrumentation==0.61b0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-proto==1.40.0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-sdk==1.40.0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-semantic-conventions==0.61b0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-util-http==0.61b0 ; python_version >= "3.12" and python_version < "3.15"
orjson==3.11.7 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-api==1.41.0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-exporter-otlp-proto-common==1.41.0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-exporter-otlp-proto-http==1.41.0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-proto==1.41.0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-sdk==1.41.0 ; python_version >= "3.12" and python_version < "3.15"
opentelemetry-semantic-conventions==0.62b0 ; python_version >= "3.12" and python_version < "3.15"
orjson==3.11.8 ; python_version >= "3.12" and python_version < "3.15"
ormsgpack==1.12.2 ; python_version >= "3.12" and python_version < "3.15"
packaging==26.0 ; python_version >= "3.12" and python_version < "3.15"
pandas==2.3.3 ; python_version == "3.14"
pandas==3.0.1 ; python_version >= "3.12" and python_version < "3.14"
pillow==12.1.1 ; python_version >= "3.12" and python_version < "3.15"
platformdirs==4.9.4 ; python_version >= "3.12" and python_version < "3.15"
pandas==3.0.2 ; python_version >= "3.12" and python_version < "3.14"
pathspec==1.0.4 ; python_version >= "3.12" and python_version < "3.15"
pillow==12.2.0 ; python_version >= "3.12" and python_version < "3.15"
platformdirs==4.9.6 ; python_version >= "3.12" and python_version < "3.15"
portalocker==2.10.1 ; python_version >= "3.13" and python_version < "3.15"
portalocker==3.2.0 ; python_version == "3.12"
posthog==7.9.12 ; python_version >= "3.12" and python_version < "3.15"
posthog==7.11.0 ; python_version >= "3.12" and python_version < "3.15"
prompt-toolkit==3.0.52 ; python_version >= "3.12" and python_version < "3.15"
propcache==0.4.1 ; python_version >= "3.12" and python_version < "3.15"
protobuf==5.29.6 ; python_version >= "3.12" and python_version < "3.15"
protobuf==6.33.6 ; python_version >= "3.12" and python_version < "3.15"
psutil==7.2.2 ; python_version >= "3.12" and python_version < "3.15"
psycopg-pool==3.3.0 ; python_version >= "3.12" and python_version < "3.15"
psycopg2-binary==2.9.11 ; python_version >= "3.12" and python_version < "3.15"
psycopg==3.3.3 ; python_version >= "3.12" and python_version < "3.15"
pyasn1-modules==0.4.2 ; python_version >= "3.12" and python_version < "3.15"
pyasn1==0.6.2 ; python_version >= "3.12" and python_version < "3.15"
pycparser==3.0 ; python_version >= "3.12" and python_version < "3.15" and implementation_name != "PyPy" and platform_python_implementation != "PyPy"
pyasn1==0.6.3 ; python_version >= "3.12" and python_version < "3.15"
pycparser==3.0 ; python_version >= "3.12" and python_version < "3.15" and platform_python_implementation != "PyPy" and implementation_name != "PyPy"
pydantic-core==2.27.2 ; python_version >= "3.12" and python_version < "3.15"
pydantic-settings==2.13.1 ; python_version >= "3.12" and python_version < "3.15"
pydantic==2.10.5 ; python_version >= "3.12" and python_version < "3.15"
pygments==2.19.2 ; python_version >= "3.12" and python_version < "3.15"
pygments==2.20.0 ; python_version >= "3.12" and python_version < "3.15"
pyjwt==2.12.1 ; python_version >= "3.12" and python_version < "3.15"
pyperclip==1.11.0 ; python_version >= "3.12" and python_version < "3.15"
python-dateutil==2.8.2 ; python_version >= "3.12" and python_version < "3.15"
python-dotenv==1.2.2 ; python_version >= "3.12" and python_version < "3.15"
python-multipart==0.0.22 ; python_version >= "3.12" and python_version < "3.15"
python-multipart==0.0.26 ; python_version >= "3.12" and python_version < "3.15"
pytz==2026.1.post1 ; python_version >= "3.12" and python_version < "3.15"
pywin32==311 ; python_version >= "3.12" and python_version < "3.15" and (sys_platform == "win32" or platform_system == "Windows")
pyyaml==6.0.3 ; python_version >= "3.12" and python_version < "3.15"
@ -156,46 +151,42 @@ qdrant-client==1.12.1 ; python_version >= "3.13" and python_version < "3.15"
qdrant-client==1.17.1 ; python_version == "3.12"
ragflow-sdk==0.23.1 ; python_version >= "3.12" and python_version < "3.15"
referencing==0.37.0 ; python_version >= "3.12" and python_version < "3.15"
regex==2026.2.28 ; python_version >= "3.12" and python_version < "3.15"
regex==2026.4.4 ; python_version >= "3.12" and python_version < "3.15"
requests-toolbelt==1.0.0 ; python_version >= "3.12" and python_version < "3.15"
requests==2.32.5 ; python_version >= "3.12" and python_version < "3.15"
rich==14.3.3 ; python_version >= "3.12" and python_version < "3.15"
rich==14.3.4 ; python_version >= "3.12" and python_version < "3.15"
rpds-py==0.30.0 ; python_version >= "3.12" and python_version < "3.15"
runloop-api-client==1.11.0 ; python_version >= "3.12" and python_version < "3.15"
safetensors==0.7.0 ; python_version >= "3.12" and python_version < "3.15"
scikit-learn==1.8.0 ; python_version >= "3.12" and python_version < "3.15"
scipy==1.17.1 ; python_version >= "3.12" and python_version < "3.15"
sentence-transformers==3.4.1 ; python_version >= "3.12" and python_version < "3.15"
setuptools==70.3.0 ; python_version >= "3.12" and python_version < "3.15"
shellingham==1.5.4 ; python_version >= "3.12" and python_version < "3.15"
six==1.17.0 ; python_version >= "3.12" and python_version < "3.15"
sniffio==1.3.1 ; python_version >= "3.12" and python_version < "3.15"
soupsieve==2.8.3 ; python_version >= "3.12" and python_version < "3.15"
sqlalchemy==2.0.48 ; python_version >= "3.12" and python_version < "3.15"
sqlite-vec==0.1.6 ; python_version >= "3.12" and python_version < "3.15"
sse-starlette==3.0.3 ; python_version >= "3.12" and python_version < "3.15"
sqlalchemy==2.0.49 ; python_version >= "3.12" and python_version < "3.15"
sqlite-vec==0.1.9 ; python_version >= "3.12" and python_version < "3.15"
sse-starlette==2.1.3 ; python_version >= "3.12" and python_version < "3.15"
starlette==0.47.3 ; python_version >= "3.12" and python_version < "3.15"
structlog==25.5.0 ; python_version >= "3.12" and python_version < "3.15"
sympy==1.14.0 ; python_version >= "3.12" and python_version < "3.15"
synchronicity==0.11.1 ; python_version >= "3.12" and python_version < "3.15"
tavily-python==0.7.23 ; python_version >= "3.12" and python_version < "3.15"
tenacity==9.1.4 ; python_version >= "3.12" and python_version < "3.15"
textual-autocomplete==4.0.6 ; python_version >= "3.12" and python_version < "3.15"
textual==8.1.1 ; python_version >= "3.12" and python_version < "3.15"
textual-speedups==0.2.1 ; python_version >= "3.12" and python_version < "3.15"
textual==8.2.3 ; python_version >= "3.12" and python_version < "3.15"
threadpoolctl==3.6.0 ; python_version >= "3.12" and python_version < "3.15"
tiktoken==0.12.0 ; python_version >= "3.12" and python_version < "3.15"
tokenizers==0.22.2 ; python_version >= "3.12" and python_version < "3.15"
toml==0.10.2 ; python_version >= "3.12" and python_version < "3.15"
tomli-w==1.2.0 ; python_version >= "3.12" and python_version < "3.15"
torch==2.2.0 ; python_version >= "3.12" and python_version < "3.15"
tqdm==4.67.3 ; python_version >= "3.12" and python_version < "3.15"
transformers==4.57.6 ; python_version >= "3.12" and python_version < "3.15"
triton==2.2.0 ; python_version >= "3.12" and python_version < "3.15" and platform_machine == "x86_64" and platform_system == "Linux"
typer==0.24.1 ; python_version >= "3.12" and python_version < "3.15"
types-certifi==2021.10.8.3 ; python_version >= "3.12" and python_version < "3.15"
types-toml==0.10.8.20240310 ; python_version >= "3.12" and python_version < "3.15"
triton==2.2.0 ; python_version >= "3.12" and python_version < "3.15" and platform_system == "Linux" and platform_machine == "x86_64"
truststore==0.10.4 ; python_version >= "3.12" and python_version < "3.15"
typing-extensions==4.15.0 ; python_version >= "3.12" and python_version < "3.15"
typing-inspection==0.4.2 ; python_version >= "3.12" and python_version < "3.15"
tzdata==2025.3 ; python_version >= "3.12" and python_version < "3.15" and (sys_platform == "win32" or sys_platform == "emscripten") or python_version == "3.14"
tzdata==2026.1 ; python_version >= "3.12" and python_version < "3.15" and (sys_platform == "win32" or sys_platform == "emscripten") or python_version == "3.14"
uc-micro-py==2.0.0 ; python_version >= "3.12" and python_version < "3.15"
urllib3==2.6.3 ; python_version >= "3.12" and python_version < "3.15"
uuid-utils==0.14.1 ; python_version >= "3.12" and python_version < "3.15"
@ -206,7 +197,6 @@ wcmatch==10.1 ; python_version >= "3.12" and python_version < "3.15"
wcwidth==0.6.0 ; python_version >= "3.12" and python_version < "3.15"
webrtcvad==2.0.10 ; python_version >= "3.12" and python_version < "3.15"
websockets==15.0.1 ; python_version >= "3.12" and python_version < "3.15"
wrapt==1.17.3 ; python_version >= "3.12" and python_version < "3.15"
wsgidav==4.3.3 ; python_version >= "3.12" and python_version < "3.15"
xlrd==2.0.2 ; python_version >= "3.12" and python_version < "3.15"
xxhash==3.6.0 ; python_version >= "3.12" and python_version < "3.15"

View File

@ -5,7 +5,6 @@ API data models and response schemas.
from typing import Dict, List, Optional, Any, AsyncGenerator
from pydantic import BaseModel, Field, field_validator, ConfigDict
from utils.settings import DEFAULT_THINKING_ENABLE
class Message(BaseModel):
role: str
@ -52,7 +51,7 @@ class ChatRequest(BaseModel):
mcp_settings: Optional[List[Dict]] = None
user_identifier: Optional[str] = ""
session_id: Optional[str] = None
enable_thinking: Optional[bool] = DEFAULT_THINKING_ENABLE
enable_thinking: Optional[bool] = False
skills: Optional[List[str]] = None
enable_memory: Optional[bool] = False
shell_env: Optional[Dict[str, str]] = None

View File

@ -12,7 +12,7 @@ MAX_OUTPUT_TOKENS = int(os.getenv("MAX_OUTPUT_TOKENS", 8000))
# 可选参数
# Summarization Settings
SUMMARIZATION_MAX_TOKENS = int(MAX_CONTEXT_TOKENS/3)
SUMMARIZATION_MAX_TOKENS = int(MAX_CONTEXT_TOKENS/2)
SUMMARIZATION_TOKENS_TO_KEEP = int(SUMMARIZATION_MAX_TOKENS/3)
DEFAULT_TRIM_TOKEN_LIMIT = SUMMARIZATION_MAX_TOKENS - SUMMARIZATION_TOKENS_TO_KEEP + 5000
@ -32,11 +32,9 @@ TOKENIZERS_PARALLELISM = os.getenv("TOKENIZERS_PARALLELISM", "true")
SENTENCE_TRANSFORMER_MODEL = os.getenv("SENTENCE_TRANSFORMER_MODEL", "TaylorAI/gte-tiny")
# Tool Output Length Control Settings
TOOL_OUTPUT_MAX_LENGTH = int(SUMMARIZATION_MAX_TOKENS/4)
TOOL_OUTPUT_MAX_LENGTH = SUMMARIZATION_MAX_TOKENS
TOOL_OUTPUT_TRUNCATION_STRATEGY = os.getenv("TOOL_OUTPUT_TRUNCATION_STRATEGY", "smart")
# THINKING ENABLE
DEFAULT_THINKING_ENABLE = os.getenv("DEFAULT_THINKING_ENABLE", "true") == "true"
# WebDAV Authentication
@ -59,7 +57,7 @@ CHECKPOINT_DB_URL = os.getenv("CHECKPOINT_DB_URL", "postgresql://postgres:AeEGDB
# 连接池大小
# 同时可以持有的最大连接数
CHECKPOINT_POOL_SIZE = int(os.getenv("CHECKPOINT_POOL_SIZE", "20"))
MEM0_POOL_SIZE = int(os.getenv("MEM0_POOL_SIZE", "20"))
MEM0_POOL_SIZE = int(os.getenv("MEM0_POOL_SIZE", "50"))
# Checkpoint 自动清理配置
# 是否启用自动清理旧 session