mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-03-18 12:40:06 +08:00
fix: windows path and encoding adaptation
This commit is contained in:
@@ -11,12 +11,18 @@ from typing import Optional, List
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def _default_workspace():
|
||||||
|
"""Get default workspace path with proper Windows support"""
|
||||||
|
from common.utils import expand_path
|
||||||
|
return expand_path("~/cow")
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MemoryConfig:
|
class MemoryConfig:
|
||||||
"""Configuration for memory storage and search"""
|
"""Configuration for memory storage and search"""
|
||||||
|
|
||||||
# Storage paths (default: ~/cow)
|
# Storage paths (default: ~/cow)
|
||||||
workspace_root: str = field(default_factory=lambda: os.path.expanduser("~/cow"))
|
workspace_root: str = field(default_factory=_default_workspace)
|
||||||
|
|
||||||
# Embedding config
|
# Embedding config
|
||||||
embedding_provider: str = "openai" # "openai" | "local"
|
embedding_provider: str = "openai" # "openai" | "local"
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ class MemoryManager:
|
|||||||
):
|
):
|
||||||
"""Sync a single file"""
|
"""Sync a single file"""
|
||||||
# Compute file hash
|
# Compute file hash
|
||||||
content = file_path.read_text()
|
content = file_path.read_text(encoding='utf-8')
|
||||||
file_hash = MemoryStorage.compute_hash(content)
|
file_hash = MemoryStorage.compute_hash(content)
|
||||||
|
|
||||||
# Get relative path
|
# Get relative path
|
||||||
|
|||||||
@@ -140,7 +140,9 @@ class Agent:
|
|||||||
if self.runtime_info.get("model"):
|
if self.runtime_info.get("model"):
|
||||||
runtime_parts.append(f"模型={self.runtime_info['model']}")
|
runtime_parts.append(f"模型={self.runtime_info['model']}")
|
||||||
if self.runtime_info.get("workspace"):
|
if self.runtime_info.get("workspace"):
|
||||||
runtime_parts.append(f"工作空间={self.runtime_info['workspace']}")
|
# Replace backslashes with forward slashes for Windows paths
|
||||||
|
workspace_path = str(self.runtime_info['workspace']).replace('\\', '/')
|
||||||
|
runtime_parts.append(f"工作空间={workspace_path}")
|
||||||
if self.runtime_info.get("channel") and self.runtime_info.get("channel") != "web":
|
if self.runtime_info.get("channel") and self.runtime_info.get("channel") != "web":
|
||||||
runtime_parts.append(f"渠道={self.runtime_info['channel']}")
|
runtime_parts.append(f"渠道={self.runtime_info['channel']}")
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from typing import Dict, Any
|
|||||||
from agent.tools.base_tool import BaseTool, ToolResult
|
from agent.tools.base_tool import BaseTool, ToolResult
|
||||||
from agent.tools.utils.truncate import truncate_tail, format_size, DEFAULT_MAX_LINES, DEFAULT_MAX_BYTES
|
from agent.tools.utils.truncate import truncate_tail, format_size, DEFAULT_MAX_LINES, DEFAULT_MAX_BYTES
|
||||||
from common.log import logger
|
from common.log import logger
|
||||||
|
from common.utils import expand_path
|
||||||
|
|
||||||
|
|
||||||
class Bash(BaseTool):
|
class Bash(BaseTool):
|
||||||
@@ -80,7 +81,7 @@ IMPORTANT SAFETY GUIDELINES:
|
|||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
|
|
||||||
# Load environment variables from ~/.cow/.env if it exists
|
# Load environment variables from ~/.cow/.env if it exists
|
||||||
env_file = os.path.expanduser("~/.cow/.env")
|
env_file = expand_path("~/.cow/.env")
|
||||||
if os.path.exists(env_file):
|
if os.path.exists(env_file):
|
||||||
try:
|
try:
|
||||||
from dotenv import dotenv_values
|
from dotenv import dotenv_values
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import os
|
|||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
|
|
||||||
from agent.tools.base_tool import BaseTool, ToolResult
|
from agent.tools.base_tool import BaseTool, ToolResult
|
||||||
|
from common.utils import expand_path
|
||||||
from agent.tools.utils.diff import (
|
from agent.tools.utils.diff import (
|
||||||
strip_bom,
|
strip_bom,
|
||||||
detect_line_ending,
|
detect_line_ending,
|
||||||
@@ -178,7 +179,7 @@ class Edit(BaseTool):
|
|||||||
:return: Absolute path
|
:return: Absolute path
|
||||||
"""
|
"""
|
||||||
# Expand ~ to user home directory
|
# Expand ~ to user home directory
|
||||||
path = os.path.expanduser(path)
|
path = expand_path(path)
|
||||||
if os.path.isabs(path):
|
if os.path.isabs(path):
|
||||||
return path
|
return path
|
||||||
return os.path.abspath(os.path.join(self.cwd, path))
|
return os.path.abspath(os.path.join(self.cwd, path))
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from agent.tools.base_tool import BaseTool, ToolResult
|
from agent.tools.base_tool import BaseTool, ToolResult
|
||||||
from common.log import logger
|
from common.log import logger
|
||||||
|
from common.utils import expand_path
|
||||||
|
|
||||||
|
|
||||||
# API Key 知识库:常见的环境变量及其描述
|
# API Key 知识库:常见的环境变量及其描述
|
||||||
@@ -66,7 +67,7 @@ class EnvConfig(BaseTool):
|
|||||||
def __init__(self, config: dict = None):
|
def __init__(self, config: dict = None):
|
||||||
self.config = config or {}
|
self.config = config or {}
|
||||||
# Store env config in ~/.cow directory (outside workspace for security)
|
# Store env config in ~/.cow directory (outside workspace for security)
|
||||||
self.env_dir = os.path.expanduser("~/.cow")
|
self.env_dir = expand_path("~/.cow")
|
||||||
self.env_path = os.path.join(self.env_dir, '.env')
|
self.env_path = os.path.join(self.env_dir, '.env')
|
||||||
self.agent_bridge = self.config.get("agent_bridge") # Reference to AgentBridge for hot reload
|
self.agent_bridge = self.config.get("agent_bridge") # Reference to AgentBridge for hot reload
|
||||||
# Don't create .env file in __init__ to avoid issues during tool discovery
|
# Don't create .env file in __init__ to avoid issues during tool discovery
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from typing import Dict, Any
|
|||||||
|
|
||||||
from agent.tools.base_tool import BaseTool, ToolResult
|
from agent.tools.base_tool import BaseTool, ToolResult
|
||||||
from agent.tools.utils.truncate import truncate_head, format_size, DEFAULT_MAX_BYTES
|
from agent.tools.utils.truncate import truncate_head, format_size, DEFAULT_MAX_BYTES
|
||||||
|
from common.utils import expand_path
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_LIMIT = 500
|
DEFAULT_LIMIT = 500
|
||||||
@@ -51,7 +52,7 @@ class Ls(BaseTool):
|
|||||||
absolute_path = self._resolve_path(path)
|
absolute_path = self._resolve_path(path)
|
||||||
|
|
||||||
# Security check: Prevent accessing sensitive config directory
|
# Security check: Prevent accessing sensitive config directory
|
||||||
env_config_dir = os.path.expanduser("~/.cow")
|
env_config_dir = expand_path("~/.cow")
|
||||||
if os.path.abspath(absolute_path) == os.path.abspath(env_config_dir):
|
if os.path.abspath(absolute_path) == os.path.abspath(env_config_dir):
|
||||||
return ToolResult.fail(
|
return ToolResult.fail(
|
||||||
"Error: Access denied. API keys and credentials must be accessed through the env_config tool only."
|
"Error: Access denied. API keys and credentials must be accessed through the env_config tool only."
|
||||||
@@ -133,7 +134,7 @@ class Ls(BaseTool):
|
|||||||
def _resolve_path(self, path: str) -> str:
|
def _resolve_path(self, path: str) -> str:
|
||||||
"""Resolve path to absolute path"""
|
"""Resolve path to absolute path"""
|
||||||
# Expand ~ to user home directory
|
# Expand ~ to user home directory
|
||||||
path = os.path.expanduser(path)
|
path = expand_path(path)
|
||||||
if os.path.isabs(path):
|
if os.path.isabs(path):
|
||||||
return path
|
return path
|
||||||
return os.path.abspath(os.path.join(self.cwd, path))
|
return os.path.abspath(os.path.join(self.cwd, path))
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class MemoryGetTool(BaseTool):
|
|||||||
if not file_path.exists():
|
if not file_path.exists():
|
||||||
return ToolResult.fail(f"Error: File not found: {path}")
|
return ToolResult.fail(f"Error: File not found: {path}")
|
||||||
|
|
||||||
content = file_path.read_text()
|
content = file_path.read_text(encoding='utf-8')
|
||||||
lines = content.split('\n')
|
lines = content.split('\n')
|
||||||
|
|
||||||
# Handle line range
|
# Handle line range
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from agent.tools.base_tool import BaseTool, ToolResult
|
from agent.tools.base_tool import BaseTool, ToolResult
|
||||||
from agent.tools.utils.truncate import truncate_head, format_size, DEFAULT_MAX_LINES, DEFAULT_MAX_BYTES
|
from agent.tools.utils.truncate import truncate_head, format_size, DEFAULT_MAX_LINES, DEFAULT_MAX_BYTES
|
||||||
|
from common.utils import expand_path
|
||||||
|
|
||||||
|
|
||||||
class Read(BaseTool):
|
class Read(BaseTool):
|
||||||
@@ -77,7 +78,7 @@ class Read(BaseTool):
|
|||||||
absolute_path = self._resolve_path(path)
|
absolute_path = self._resolve_path(path)
|
||||||
|
|
||||||
# Security check: Prevent reading sensitive config files
|
# Security check: Prevent reading sensitive config files
|
||||||
env_config_path = os.path.expanduser("~/.cow/.env")
|
env_config_path = expand_path("~/.cow/.env")
|
||||||
if os.path.abspath(absolute_path) == os.path.abspath(env_config_path):
|
if os.path.abspath(absolute_path) == os.path.abspath(env_config_path):
|
||||||
return ToolResult.fail(
|
return ToolResult.fail(
|
||||||
"Error: Access denied. API keys and credentials must be accessed through the env_config tool only."
|
"Error: Access denied. API keys and credentials must be accessed through the env_config tool only."
|
||||||
@@ -129,7 +130,7 @@ class Read(BaseTool):
|
|||||||
:return: Absolute path
|
:return: Absolute path
|
||||||
"""
|
"""
|
||||||
# Expand ~ to user home directory
|
# Expand ~ to user home directory
|
||||||
path = os.path.expanduser(path)
|
path = expand_path(path)
|
||||||
if os.path.isabs(path):
|
if os.path.isabs(path):
|
||||||
return path
|
return path
|
||||||
return os.path.abspath(os.path.join(self.cwd, path))
|
return os.path.abspath(os.path.join(self.cwd, path))
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import os
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
from config import conf
|
from config import conf
|
||||||
from common.log import logger
|
from common.log import logger
|
||||||
|
from common.utils import expand_path
|
||||||
from bridge.context import Context, ContextType
|
from bridge.context import Context, ContextType
|
||||||
from bridge.reply import Reply, ReplyType
|
from bridge.reply import Reply, ReplyType
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ def init_scheduler(agent_bridge) -> bool:
|
|||||||
from agent.tools.scheduler.scheduler_service import SchedulerService
|
from agent.tools.scheduler.scheduler_service import SchedulerService
|
||||||
|
|
||||||
# Get workspace from config
|
# Get workspace from config
|
||||||
workspace_root = os.path.expanduser(conf().get("agent_workspace", "~/cow"))
|
workspace_root = expand_path(conf().get("agent_workspace", "~/cow"))
|
||||||
store_path = os.path.join(workspace_root, "scheduler", "tasks.json")
|
store_path = os.path.join(workspace_root, "scheduler", "tasks.json")
|
||||||
|
|
||||||
# Create task store
|
# Create task store
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import threading
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from common.utils import expand_path
|
||||||
|
|
||||||
|
|
||||||
class TaskStore:
|
class TaskStore:
|
||||||
@@ -24,7 +25,7 @@ class TaskStore:
|
|||||||
"""
|
"""
|
||||||
if store_path is None:
|
if store_path is None:
|
||||||
# Default to ~/cow/scheduler/tasks.json
|
# Default to ~/cow/scheduler/tasks.json
|
||||||
home = os.path.expanduser("~")
|
home = expand_path("~")
|
||||||
store_path = os.path.join(home, "cow", "scheduler", "tasks.json")
|
store_path = os.path.join(home, "cow", "scheduler", "tasks.json")
|
||||||
|
|
||||||
self.store_path = store_path
|
self.store_path = store_path
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from typing import Dict, Any
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from agent.tools.base_tool import BaseTool, ToolResult
|
from agent.tools.base_tool import BaseTool, ToolResult
|
||||||
|
from common.utils import expand_path
|
||||||
|
|
||||||
|
|
||||||
class Send(BaseTool):
|
class Send(BaseTool):
|
||||||
@@ -102,7 +103,7 @@ class Send(BaseTool):
|
|||||||
|
|
||||||
def _resolve_path(self, path: str) -> str:
|
def _resolve_path(self, path: str) -> str:
|
||||||
"""Resolve path to absolute path"""
|
"""Resolve path to absolute path"""
|
||||||
path = os.path.expanduser(path)
|
path = expand_path(path)
|
||||||
if os.path.isabs(path):
|
if os.path.isabs(path):
|
||||||
return path
|
return path
|
||||||
return os.path.abspath(os.path.join(self.cwd, path))
|
return os.path.abspath(os.path.join(self.cwd, path))
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from typing import Dict, Any
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from agent.tools.base_tool import BaseTool, ToolResult
|
from agent.tools.base_tool import BaseTool, ToolResult
|
||||||
|
from common.utils import expand_path
|
||||||
|
|
||||||
|
|
||||||
class Write(BaseTool):
|
class Write(BaseTool):
|
||||||
@@ -90,7 +91,7 @@ class Write(BaseTool):
|
|||||||
:return: Absolute path
|
:return: Absolute path
|
||||||
"""
|
"""
|
||||||
# Expand ~ to user home directory
|
# Expand ~ to user home directory
|
||||||
path = os.path.expanduser(path)
|
path = expand_path(path)
|
||||||
if os.path.isabs(path):
|
if os.path.isabs(path):
|
||||||
return path
|
return path
|
||||||
return os.path.abspath(os.path.join(self.cwd, path))
|
return os.path.abspath(os.path.join(self.cwd, path))
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from bridge.context import Context
|
|||||||
from bridge.reply import Reply, ReplyType
|
from bridge.reply import Reply, ReplyType
|
||||||
from common import const
|
from common import const
|
||||||
from common.log import logger
|
from common.log import logger
|
||||||
|
from common.utils import expand_path
|
||||||
from models.openai_compatible_bot import OpenAICompatibleBot
|
from models.openai_compatible_bot import OpenAICompatibleBot
|
||||||
|
|
||||||
|
|
||||||
@@ -421,7 +422,7 @@ class AgentBridge:
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Use fixed secure location for .env file
|
# Use fixed secure location for .env file
|
||||||
env_file = os.path.expanduser("~/.cow/.env")
|
env_file = expand_path("~/.cow/.env")
|
||||||
|
|
||||||
# Read existing env vars from .env file
|
# Read existing env vars from .env file
|
||||||
existing_env_vars = {}
|
existing_env_vars = {}
|
||||||
@@ -504,7 +505,7 @@ class AgentBridge:
|
|||||||
from config import conf
|
from config import conf
|
||||||
|
|
||||||
# Reload environment variables from .env file
|
# Reload environment variables from .env file
|
||||||
workspace_root = os.path.expanduser(conf().get("agent_workspace", "~/cow"))
|
workspace_root = expand_path(conf().get("agent_workspace", "~/cow"))
|
||||||
env_file = os.path.join(workspace_root, '.env')
|
env_file = os.path.join(workspace_root, '.env')
|
||||||
|
|
||||||
if os.path.exists(env_file):
|
if os.path.exists(env_file):
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from typing import Optional, List
|
|||||||
from agent.protocol import Agent
|
from agent.protocol import Agent
|
||||||
from agent.tools import ToolManager
|
from agent.tools import ToolManager
|
||||||
from common.log import logger
|
from common.log import logger
|
||||||
|
from common.utils import expand_path
|
||||||
|
|
||||||
|
|
||||||
class AgentInitializer:
|
class AgentInitializer:
|
||||||
@@ -46,7 +47,7 @@ class AgentInitializer:
|
|||||||
from config import conf
|
from config import conf
|
||||||
|
|
||||||
# Get workspace from config
|
# Get workspace from config
|
||||||
workspace_root = os.path.expanduser(conf().get("agent_workspace", "~/cow"))
|
workspace_root = expand_path(conf().get("agent_workspace", "~/cow"))
|
||||||
|
|
||||||
# Migrate API keys
|
# Migrate API keys
|
||||||
self._migrate_config_to_env(workspace_root)
|
self._migrate_config_to_env(workspace_root)
|
||||||
@@ -122,7 +123,7 @@ class AgentInitializer:
|
|||||||
|
|
||||||
def _load_env_file(self):
|
def _load_env_file(self):
|
||||||
"""Load environment variables from .env file"""
|
"""Load environment variables from .env file"""
|
||||||
env_file = os.path.expanduser("~/.cow/.env")
|
env_file = expand_path("~/.cow/.env")
|
||||||
if os.path.exists(env_file):
|
if os.path.exists(env_file):
|
||||||
try:
|
try:
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
@@ -338,7 +339,7 @@ class AgentInitializer:
|
|||||||
"linkai_api_key": "LINKAI_API_KEY",
|
"linkai_api_key": "LINKAI_API_KEY",
|
||||||
}
|
}
|
||||||
|
|
||||||
env_file = os.path.expanduser("~/.cow/.env")
|
env_file = expand_path("~/.cow/.env")
|
||||||
|
|
||||||
# Read existing env vars
|
# Read existing env vars
|
||||||
existing_env_vars = {}
|
existing_env_vars = {}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from dingtalk_stream.card_replier import CardReplier
|
|||||||
from bridge.context import Context, ContextType
|
from bridge.context import Context, ContextType
|
||||||
from bridge.reply import Reply, ReplyType
|
from bridge.reply import Reply, ReplyType
|
||||||
from channel.chat_channel import ChatChannel
|
from channel.chat_channel import ChatChannel
|
||||||
|
from common.utils import expand_path
|
||||||
from channel.dingtalk.dingtalk_message import DingTalkMessage
|
from channel.dingtalk.dingtalk_message import DingTalkMessage
|
||||||
from common.expired_dict import ExpiredDict
|
from common.expired_dict import ExpiredDict
|
||||||
from common.log import logger
|
from common.log import logger
|
||||||
@@ -276,7 +277,7 @@ class DingTalkChanel(ChatChannel, dingtalk_stream.ChatbotHandler):
|
|||||||
|
|
||||||
# 保存到临时文件
|
# 保存到临时文件
|
||||||
file_name = os.path.basename(file_path) or f"media_{uuid.uuid4()}"
|
file_name = os.path.basename(file_path) or f"media_{uuid.uuid4()}"
|
||||||
workspace_root = os.path.expanduser(conf().get("agent_workspace", "~/cow"))
|
workspace_root = expand_path(conf().get("agent_workspace", "~/cow"))
|
||||||
tmp_dir = os.path.join(workspace_root, "tmp")
|
tmp_dir = os.path.join(workspace_root, "tmp")
|
||||||
os.makedirs(tmp_dir, exist_ok=True)
|
os.makedirs(tmp_dir, exist_ok=True)
|
||||||
temp_file = os.path.join(tmp_dir, file_name)
|
temp_file = os.path.join(tmp_dir, file_name)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from channel.chat_message import ChatMessage
|
|||||||
# -*- coding=utf-8 -*-
|
# -*- coding=utf-8 -*-
|
||||||
from common.log import logger
|
from common.log import logger
|
||||||
from common.tmp_dir import TmpDir
|
from common.tmp_dir import TmpDir
|
||||||
|
from common.utils import expand_path
|
||||||
from config import conf
|
from config import conf
|
||||||
|
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ class DingTalkMessage(ChatMessage):
|
|||||||
download_url = image_download_handler.get_image_download_url(download_code)
|
download_url = image_download_handler.get_image_download_url(download_code)
|
||||||
|
|
||||||
# 下载到工作空间 tmp 目录
|
# 下载到工作空间 tmp 目录
|
||||||
workspace_root = os.path.expanduser(conf().get("agent_workspace", "~/cow"))
|
workspace_root = expand_path(conf().get("agent_workspace", "~/cow"))
|
||||||
tmp_dir = os.path.join(workspace_root, "tmp")
|
tmp_dir = os.path.join(workspace_root, "tmp")
|
||||||
os.makedirs(tmp_dir, exist_ok=True)
|
os.makedirs(tmp_dir, exist_ok=True)
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ class DingTalkMessage(ChatMessage):
|
|||||||
self.ctype = ContextType.TEXT
|
self.ctype = ContextType.TEXT
|
||||||
|
|
||||||
# 下载到工作空间 tmp 目录
|
# 下载到工作空间 tmp 目录
|
||||||
workspace_root = os.path.expanduser(conf().get("agent_workspace", "~/cow"))
|
workspace_root = expand_path(conf().get("agent_workspace", "~/cow"))
|
||||||
tmp_dir = os.path.join(workspace_root, "tmp")
|
tmp_dir = os.path.join(workspace_root, "tmp")
|
||||||
os.makedirs(tmp_dir, exist_ok=True)
|
os.makedirs(tmp_dir, exist_ok=True)
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import requests
|
|||||||
from common.log import logger
|
from common.log import logger
|
||||||
from common.tmp_dir import TmpDir
|
from common.tmp_dir import TmpDir
|
||||||
from common import utils
|
from common import utils
|
||||||
|
from common.utils import expand_path
|
||||||
from config import conf
|
from config import conf
|
||||||
|
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ class FeishuMessage(ChatMessage):
|
|||||||
image_key = content.get("image_key")
|
image_key = content.get("image_key")
|
||||||
|
|
||||||
# 下载图片到工作空间临时目录
|
# 下载图片到工作空间临时目录
|
||||||
workspace_root = os.path.expanduser(conf().get("agent_workspace", "~/cow"))
|
workspace_root = expand_path(conf().get("agent_workspace", "~/cow"))
|
||||||
tmp_dir = os.path.join(workspace_root, "tmp")
|
tmp_dir = os.path.join(workspace_root, "tmp")
|
||||||
os.makedirs(tmp_dir, exist_ok=True)
|
os.makedirs(tmp_dir, exist_ok=True)
|
||||||
image_path = os.path.join(tmp_dir, f"{image_key}.png")
|
image_path = os.path.join(tmp_dir, f"{image_key}.png")
|
||||||
@@ -97,7 +98,7 @@ class FeishuMessage(ChatMessage):
|
|||||||
|
|
||||||
if image_keys:
|
if image_keys:
|
||||||
# 如果包含图片,下载并在文本中引用本地路径
|
# 如果包含图片,下载并在文本中引用本地路径
|
||||||
workspace_root = os.path.expanduser(conf().get("agent_workspace", "~/cow"))
|
workspace_root = expand_path(conf().get("agent_workspace", "~/cow"))
|
||||||
tmp_dir = os.path.join(workspace_root, "tmp")
|
tmp_dir = os.path.join(workspace_root, "tmp")
|
||||||
os.makedirs(tmp_dir, exist_ok=True)
|
os.makedirs(tmp_dir, exist_ok=True)
|
||||||
|
|
||||||
|
|||||||
@@ -76,3 +76,42 @@ def remove_markdown_symbol(text: str):
|
|||||||
if not text:
|
if not text:
|
||||||
return text
|
return text
|
||||||
return re.sub(r'\*\*(.*?)\*\*', r'\1', text)
|
return re.sub(r'\*\*(.*?)\*\*', r'\1', text)
|
||||||
|
|
||||||
|
|
||||||
|
def expand_path(path: str) -> str:
|
||||||
|
"""
|
||||||
|
Expand user path with proper Windows support.
|
||||||
|
|
||||||
|
On Windows, os.path.expanduser('~') may not work properly in some shells (like PowerShell).
|
||||||
|
This function provides a more robust path expansion.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: Path string that may contain ~
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Expanded absolute path
|
||||||
|
"""
|
||||||
|
if not path:
|
||||||
|
return path
|
||||||
|
|
||||||
|
# Try standard expansion first
|
||||||
|
expanded = os.path.expanduser(path)
|
||||||
|
|
||||||
|
# If expansion didn't work (path still starts with ~), use HOME or USERPROFILE
|
||||||
|
if expanded.startswith('~'):
|
||||||
|
import platform
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
# On Windows, try USERPROFILE first, then HOME
|
||||||
|
home = os.environ.get('USERPROFILE') or os.environ.get('HOME')
|
||||||
|
else:
|
||||||
|
# On Unix-like systems, use HOME
|
||||||
|
home = os.environ.get('HOME')
|
||||||
|
|
||||||
|
if home:
|
||||||
|
# Replace ~ with home directory
|
||||||
|
if path == '~':
|
||||||
|
expanded = home
|
||||||
|
elif path.startswith('~/') or path.startswith('~\\'):
|
||||||
|
expanded = os.path.join(home, path[2:])
|
||||||
|
|
||||||
|
return expanded
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ Cow项目从简单的聊天机器人全面升级为超级智能助理 **CowAgent
|
|||||||
|
|
||||||
#### 3.2 搜索和图像识别
|
#### 3.2 搜索和图像识别
|
||||||
|
|
||||||
- **搜索技能:** 系统内置实现了 `bocha-search`(博查搜索)的Skill,依赖环境变量 `BOCHA_SEARCH_API_KEY`,可在[控制台]()进行创建,并发送给Agent完成配置
|
- **搜索技能:** 系统内置实现了 `bocha-search`(博查搜索)的Skill,依赖环境变量 `BOCHA_SEARCH_API_KEY`,可在[控制台](https://open.bochaai.com/)进行创建,并发送给Agent完成配置
|
||||||
- **图像识别技能:** 实现了 `openai-image-vision` 插件,可使用 gpt-4.1-mini、gpt-4.1 等图像识别模型。依赖秘钥 `OPENAI_API_KEY`,可通过config.json或env_config工具进行维护。
|
- **图像识别技能:** 实现了 `openai-image-vision` 插件,可使用 gpt-4.1-mini、gpt-4.1 等图像识别模型。依赖秘钥 `OPENAI_API_KEY`,可通过config.json或env_config工具进行维护。
|
||||||
|
|
||||||
<img width="800" src="https://cdn.link-ai.tech/doc/20260202213219.png">
|
<img width="800" src="https://cdn.link-ai.tech/doc/20260202213219.png">
|
||||||
|
|||||||
Reference in New Issue
Block a user