tina-python 0.7.1__tar.gz → 0.7.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tina_python-0.7.1/tina_python.egg-info → tina_python-0.7.2}/PKG-INFO +70 -61
- {tina_python-0.7.1 → tina_python-0.7.2}/README.md +67 -58
- {tina_python-0.7.1 → tina_python-0.7.2}/pyproject.toml +5 -3
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/__init__.py +1 -1
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/agent.py +29 -3
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/tools.py +5 -2
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/multimodal_agent.py +3 -1
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/llm/__init__.py +1 -2
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/llm/base_api.py +28 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/llm/files_api.py +14 -7
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/__init__.py +4 -0
- tina_python-0.7.2/tina/utils/coding_context.py +253 -0
- tina_python-0.7.2/tina/utils/coding_tools.py +689 -0
- tina_python-0.7.2/tina/utils/session_store.py +331 -0
- {tina_python-0.7.1 → tina_python-0.7.2/tina_python.egg-info}/PKG-INFO +70 -61
- {tina_python-0.7.1 → tina_python-0.7.2}/tina_python.egg-info/SOURCES.txt +3 -1
- {tina_python-0.7.1 → tina_python-0.7.2}/tina_python.egg-info/requires.txt +2 -2
- tina_python-0.7.1/tina/utils/system_tools.py +0 -547
- {tina_python-0.7.1 → tina_python-0.7.2}/LICENSE +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/MANIFEST.in +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/setup.cfg +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/setup.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/__init__.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/__init__.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/agent_response.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/agent_runtime.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/context_manager.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/events.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/executor.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/keyword_actions.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/prompt.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/state.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/core/__init__.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/core/error.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/core/logger.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/llm/base_multimodal_api.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/mcp/__init__.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/mcp/client.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/mcp/mcp_tools_executor.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/py.typed +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/agent_worker.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/deepseek.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/doc_parser.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/env_reader.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/__init__.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/environment.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/message.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/message_bus.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/web/__init__.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/web/server.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multimodal_formatter.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/output_parser.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/run_agent_in_cli.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/tui/__init__.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/tui/context_manager.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/tui/token.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/tui/tui.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/type_mapper.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/url.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/usage.py +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina_python.egg-info/dependency_links.txt +0 -0
- {tina_python-0.7.1 → tina_python-0.7.2}/tina_python.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tina-python
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: tina is in your computer!
|
|
5
5
|
Home-page: https://gitee.com/wang-churi/tina
|
|
6
6
|
Author: 王出日
|
|
@@ -18,7 +18,7 @@ License-File: LICENSE
|
|
|
18
18
|
Requires-Dist: httpx
|
|
19
19
|
Requires-Dist: python-dotenv
|
|
20
20
|
Provides-Extra: tui
|
|
21
|
-
Requires-Dist: tina-tui>=0.
|
|
21
|
+
Requires-Dist: tina-tui>=0.2.0; extra == "tui"
|
|
22
22
|
Provides-Extra: multi-agent
|
|
23
23
|
Requires-Dist: tina-multi-agent>=0.1.0; extra == "multi-agent"
|
|
24
24
|
Provides-Extra: mcp
|
|
@@ -28,7 +28,7 @@ Requires-Dist: pytest>=9.0; extra == "test"
|
|
|
28
28
|
Requires-Dist: pytest-asyncio>=1.4; extra == "test"
|
|
29
29
|
Requires-Dist: pytest-cov>=7.0; extra == "test"
|
|
30
30
|
Provides-Extra: all
|
|
31
|
-
Requires-Dist: tina-tui>=0.
|
|
31
|
+
Requires-Dist: tina-tui>=0.2.0; extra == "all"
|
|
32
32
|
Requires-Dist: tina-multi-agent>=0.1.0; extra == "all"
|
|
33
33
|
Requires-Dist: mcp>=2.0; extra == "all"
|
|
34
34
|
Dynamic: author
|
|
@@ -75,7 +75,7 @@ from tina.llm import BaseAPI
|
|
|
75
75
|
# 1. 实例化大模型(支持通过 tina.env 文件配置)
|
|
76
76
|
llm = BaseAPI(
|
|
77
77
|
api_key="your-api-key",
|
|
78
|
-
base_url="https://api.openai.com/v1
|
|
78
|
+
base_url="https://api.openai.com/v1",
|
|
79
79
|
model="gpt-4o"
|
|
80
80
|
)
|
|
81
81
|
|
|
@@ -164,7 +164,7 @@ llm = BaseAPI()
|
|
|
164
164
|
# 或者:手动传入参数
|
|
165
165
|
llm = BaseAPI(
|
|
166
166
|
api_key="your-api-key",
|
|
167
|
-
base_url="https://api.openai.com/v1
|
|
167
|
+
base_url="https://api.openai.com/v1",
|
|
168
168
|
model="gpt-4o"
|
|
169
169
|
)
|
|
170
170
|
```
|
|
@@ -172,11 +172,11 @@ llm = BaseAPI(
|
|
|
172
172
|
`tina.env` 文件示例:
|
|
173
173
|
```env
|
|
174
174
|
LLM_API_KEY="your-api-key"
|
|
175
|
-
BASE_URL="https://api.openai.com/v1
|
|
175
|
+
BASE_URL="https://api.openai.com/v1"
|
|
176
176
|
MODEL_NAME="gpt-4o"
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
-
>
|
|
179
|
+
> **base_url 规则(0.7.0 起)**:只写服务根地址即可(如 `https://api.openai.com/v1`),tina 会自动补上 `/chat/completions`;写完整地址(`.../chat/completions`)也依然兼容。旧文档要求"必须自带 `/chat/completions`"的说法已作废。
|
|
180
180
|
|
|
181
181
|
### 1.2 非流式调用
|
|
182
182
|
|
|
@@ -902,55 +902,7 @@ message = build_multimodal_message(
|
|
|
902
902
|
|
|
903
903
|
tina 提供了一些开箱即用的工具函数和工具包,帮助你快速搭建应用。
|
|
904
904
|
|
|
905
|
-
### 6.1
|
|
906
|
-
|
|
907
|
-
tina 自带一套系统工具包,包含文件操作、代码执行等常用功能:
|
|
908
|
-
|
|
909
|
-
```python
|
|
910
|
-
from tina import Agent, Tools
|
|
911
|
-
from tina.llm import BaseAPI
|
|
912
|
-
from tina.utils.system_tools import system_tools
|
|
913
|
-
|
|
914
|
-
tools = Tools(name="my_tools")
|
|
915
|
-
tools += system_tools # 添加 tina 自带的系统工具包(工具集需命名)
|
|
916
|
-
|
|
917
|
-
agent = Agent(
|
|
918
|
-
llm=BaseAPI(),
|
|
919
|
-
tools=tools,
|
|
920
|
-
system_prompt="你是一个系统助手,可以帮助我管理文件和执行代码"
|
|
921
|
-
)
|
|
922
|
-
|
|
923
|
-
result = agent.predict(instruction="帮我看看当前目录下有哪些文件", stream=True)
|
|
924
|
-
for chunk in result:
|
|
925
|
-
print(chunk.content, end="")
|
|
926
|
-
```
|
|
927
|
-
|
|
928
|
-
**内置工具一览:**
|
|
929
|
-
|
|
930
|
-
| 工具名称 | 需要确认 | 功能说明 |
|
|
931
|
-
|---------|---------|---------|
|
|
932
|
-
| `get_time` | ❌ | 获取当前系统时间 |
|
|
933
|
-
| `list_dir` | ❌ | 列出目录下的文件和子目录 |
|
|
934
|
-
| `project_tree` | ❌ | 获取项目目录结构(类似 tree 命令) |
|
|
935
|
-
| `get_path` | ❌ | 获取文件/文件夹的绝对路径 |
|
|
936
|
-
| `read_code` | ❌ | 按字符范围读取文件内容片段 |
|
|
937
|
-
| `read_code_by_line` | ❌ | 按行读取代码片段(带行号) |
|
|
938
|
-
| `search_in_files` | ❌ | 在项目中按正则搜索文本(自动忽略 `.git`/`.venv` 等) |
|
|
939
|
-
| `delay` | ❌ | 延时函数 |
|
|
940
|
-
| `make_dir` | ✅ | 创建目录(自动创建父目录) |
|
|
941
|
-
| `write_code` | ✅ | 写入文件内容(覆盖,自动创建父目录) |
|
|
942
|
-
| `append_code` | ✅ | 追加写入文件内容(自动创建父目录) |
|
|
943
|
-
| `delete_path` | ✅ | 删除文件或目录(`recursive=True` 可递归) |
|
|
944
|
-
| `replace_code_by_lines` | ✅ | 按行范围替换代码块 |
|
|
945
|
-
| `terminal` | ✅ | 在终端运行指令(带超时) |
|
|
946
|
-
| `run_python` | ✅ | 执行一小段 Python 代码 |
|
|
947
|
-
| `shot_down_system` | ✅ | 关机 |
|
|
948
|
-
|
|
949
|
-
> `需要确认` 的工具在执行时会触发 `on_tool_confirmation` 事件,适合接入人工审批流程。
|
|
950
|
-
>
|
|
951
|
-
> 由于系统工具包使用了命名空间,工具在模型侧的实际名称为 `tina_sys_tools_{名称}`,例如 `tina_sys_tools_read_code`。
|
|
952
|
-
|
|
953
|
-
### 6.2 后台工作器 `AgentWorker`
|
|
905
|
+
### 6.1 后台工作器 `AgentWorker`
|
|
954
906
|
|
|
955
907
|
`AgentWorker` 将 Agent 包装为异步后台服务,通过消息队列接收外部指令并持续处理:
|
|
956
908
|
|
|
@@ -990,7 +942,7 @@ asyncio.run(main())
|
|
|
990
942
|
|
|
991
943
|
`AgentWorker` 还会将自身的 `put` 方法自动注册为 Agent 的工具,方便多 Agent 场景下互相调用。
|
|
992
944
|
|
|
993
|
-
### 6.
|
|
945
|
+
### 6.2 终端交互控制台 `run_agent_in_cli`
|
|
994
946
|
|
|
995
947
|
快速启动一个 Agent 交互式终端,适合调试和测试:
|
|
996
948
|
|
|
@@ -1016,7 +968,7 @@ run_agent_in_cli(agent)
|
|
|
1016
968
|
| `#clear` | 清屏 |
|
|
1017
969
|
| `exit` / `quit` | 退出对话(`#exit` 不支持,会被当作普通输入) |
|
|
1018
970
|
|
|
1019
|
-
### 6.
|
|
971
|
+
### 6.3 多模态消息构建器 `build_multimodal_message`
|
|
1020
972
|
|
|
1021
973
|
用于灵活构建包含多模态内容的消息:
|
|
1022
974
|
|
|
@@ -1039,7 +991,7 @@ print(message)
|
|
|
1039
991
|
|
|
1040
992
|
## 七、拓展包(可选)
|
|
1041
993
|
|
|
1042
|
-
|
|
994
|
+
除核心之外的可选能力:有**随主包提供**的(编码工具),也有拆成**独立发行包**的(终端界面、多 Agent 环境),按需安装、可独立更新与发布。主包内不再包含后者的实现(仅保留 `tina.utils.*` 兼容转发壳)。
|
|
1043
995
|
|
|
1044
996
|
### 7.1 终端界面 TUI(`tina-tui`)
|
|
1045
997
|
|
|
@@ -1049,6 +1001,21 @@ tina 核心保持轻量:终端界面与多 Agent 环境这两块较大的功
|
|
|
1049
1001
|
pip install tina-python[tui] # 等价于安装 tina-tui
|
|
1050
1002
|
```
|
|
1051
1003
|
|
|
1004
|
+
**开箱即用的 `tinacode` 命令**:装好后可以在任意目录直接起一个编码 agent,不用写 Python:
|
|
1005
|
+
|
|
1006
|
+
```bash
|
|
1007
|
+
cd <你的项目>
|
|
1008
|
+
tinacode
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
- 工作目录 = 你敲命令时所在的目录(`code_*` 工具的相对路径以它为准)
|
|
1012
|
+
- 会话历史存到 `<cwd>/.tina/chat_sessions/`,**按目录隔离**
|
|
1013
|
+
- 模型配置读 `<cwd>/tina.env` 或 `.env`,没有则回退全局 `~/.tina/tina.env`
|
|
1014
|
+
- 目录里的 `.tinacode.md` / `AGENTS.md` / `.tina.md` 自动注入系统提示(目录级定制不用改代码)
|
|
1015
|
+
- 工具集是 `CodingTools`(见 [7.3](#73-编码工具codingtools))
|
|
1016
|
+
|
|
1017
|
+
自己组装 Agent 再交给 TUI:
|
|
1018
|
+
|
|
1052
1019
|
```python
|
|
1053
1020
|
from tina import Agent, Tools
|
|
1054
1021
|
from tina.llm import BaseAPI
|
|
@@ -1069,8 +1036,9 @@ run_agent_in_tui(agent, max_tokens=32000)
|
|
|
1069
1036
|
- 自动为 Agent 注册工具确认事件(`require_confirmation=True` 的工具会弹出选择条)
|
|
1070
1037
|
- 上下文 token 占用与上限进度(显示百分比,≥80% 变黄、超限变红警告),运行时显示动画
|
|
1071
1038
|
- `Esc` 可打断本轮回复;已生成的部分正文写回上下文,进行中的工具调用记为「该次调用被打断」
|
|
1072
|
-
- 输入框支持多行与粘贴;`Enter` 发送、`Shift+Enter` 换行、`Tab`
|
|
1039
|
+
- 输入框支持多行与粘贴;`Enter` 发送、`Shift+Enter` 换行、`Tab` 补全命令与会话 id
|
|
1073
1040
|
- 底部粘性滚动:在底部时自动跟随输出,向上滚动查看历史时不会被打扰,滚回底部自动恢复
|
|
1041
|
+
- 会话自动归档到 `<项目>/.tina/chat_sessions/`:可切换 / 重命名 / 删除,首轮结束后自动起名
|
|
1074
1042
|
- 可选 `unlimited_context=True`:用 tina 提供的无限制上下文管理器替换 Agent 的(不裁剪历史、不截断工具结果)
|
|
1075
1043
|
|
|
1076
1044
|
| 指令 | 功能 |
|
|
@@ -1080,6 +1048,11 @@ run_agent_in_tui(agent, max_tokens=32000)
|
|
|
1080
1048
|
| `#context` | 查看当前上下文 |
|
|
1081
1049
|
| `#model` | 查看当前模型信息 |
|
|
1082
1050
|
| `#tokens` | 查看当前上下文 token 占用 |
|
|
1051
|
+
| `#sessions` | 列出已保存的会话(可跟关键字过滤) |
|
|
1052
|
+
| `#switch` | 切换会话(按 id / id 前缀 / 标题) |
|
|
1053
|
+
| `#new` | 新建会话(当前会话自动保存) |
|
|
1054
|
+
| `#rename` | 重命名当前会话 |
|
|
1055
|
+
| `#delete` | 删除会话 |
|
|
1083
1056
|
| `#compact` | 压缩上下文(让 Agent 自我总结并并入 system) |
|
|
1084
1057
|
| `#clear` | 清空上下文与界面 |
|
|
1085
1058
|
| `#exit` | 退出 |
|
|
@@ -1119,6 +1092,42 @@ MultiAgentWeb(env, port=7077).run()
|
|
|
1119
1092
|
|
|
1120
1093
|
> 兼容提示:旧路径 `tina.utils.multi_agent` 仍可用(主包内保留转发壳);未安装 `tina-multi-agent` 时会提示安装。
|
|
1121
1094
|
|
|
1095
|
+
### 7.3 编码工具(`CodingTools`)
|
|
1096
|
+
|
|
1097
|
+
面向「写代码」的**主包内置**能力(命名空间 `code`),像普通工具包一样按需搭配到任意 Agent:一个编码工具包 + 一个项目感知的上下文管理器。提供可靠的**局部编辑**(精确文本匹配 + 唯一性校验 + 原子写)、搜索增强与命令输出截断。
|
|
1098
|
+
|
|
1099
|
+
```python
|
|
1100
|
+
from tina import Agent
|
|
1101
|
+
from tina.utils.coding_tools import CodingTools
|
|
1102
|
+
|
|
1103
|
+
tools = CodingTools(root=".").get_tools() # code_read / code_glob / code_grep / code_write / code_edit / code_patch / code_bash
|
|
1104
|
+
agent = Agent(llm=llm, tools=tools)
|
|
1105
|
+
```
|
|
1106
|
+
|
|
1107
|
+
| 工具 | 说明 | 需确认 |
|
|
1108
|
+
|------|------|--------|
|
|
1109
|
+
| `code_read` | 按行读取(offset/limit、行号、总行数与截断提示) | 否 |
|
|
1110
|
+
| `code_glob` | 按 glob 查找文件(如 `**/*.py`) | 否 |
|
|
1111
|
+
| `code_grep` | 正则搜索(`include` / 上下文行 / 忽略大小写) | 否 |
|
|
1112
|
+
| `code_write` | 整文件写入(`.py` 写前语法校验) | ✅ |
|
|
1113
|
+
| `code_edit` | 精确文本替换(命中多次需 `replace_all`,返回 diff) | ✅ |
|
|
1114
|
+
| `code_patch` | 应用 unified diff 补丁(一次多处/跨行改动,行号可偏差、上下文对不上则整体中止) | ✅ |
|
|
1115
|
+
| `code_bash` | 执行命令(首尾截断、带 exit code) | ✅ |
|
|
1116
|
+
|
|
1117
|
+
配套的项目感知上下文管理器(自动注入 `AGENTS.md` / `.tinacode.md` / `.tina.md`、工作目录与目录结构摘要,可用 `refresh_project_context()` 刷新):
|
|
1118
|
+
|
|
1119
|
+
既可在构造时传入,也可之后替换:
|
|
1120
|
+
|
|
1121
|
+
```python
|
|
1122
|
+
from tina import Agent
|
|
1123
|
+
from tina.utils.coding_context import CodingContextManager
|
|
1124
|
+
|
|
1125
|
+
agent = Agent(llm=llm, tools=tools, context_manager=CodingContextManager(root="."))
|
|
1126
|
+
# 或:agent.set_context_manager(CodingContextManager(root="."))
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
> 未显式传 `system_prompt` 时,Agent 会**保留** `context_manager` 自带的系统提示(不再用默认提示覆盖);显式传 `system_prompt` 才会覆盖它。
|
|
1130
|
+
|
|
1122
1131
|
---
|
|
1123
1132
|
|
|
1124
1133
|
## 附录
|
|
@@ -1129,7 +1138,7 @@ tina 支持通过环境文件配置 API 信息,自动从当前目录查找 `.e
|
|
|
1129
1138
|
|
|
1130
1139
|
```env
|
|
1131
1140
|
LLM_API_KEY="your-api-key"
|
|
1132
|
-
BASE_URL="https://api.openai.com/v1
|
|
1141
|
+
BASE_URL="https://api.openai.com/v1"
|
|
1133
1142
|
MODEL_NAME="gpt-4o"
|
|
1134
1143
|
MAX_INPUT=8000
|
|
1135
1144
|
```
|
|
@@ -37,7 +37,7 @@ from tina.llm import BaseAPI
|
|
|
37
37
|
# 1. 实例化大模型(支持通过 tina.env 文件配置)
|
|
38
38
|
llm = BaseAPI(
|
|
39
39
|
api_key="your-api-key",
|
|
40
|
-
base_url="https://api.openai.com/v1
|
|
40
|
+
base_url="https://api.openai.com/v1",
|
|
41
41
|
model="gpt-4o"
|
|
42
42
|
)
|
|
43
43
|
|
|
@@ -126,7 +126,7 @@ llm = BaseAPI()
|
|
|
126
126
|
# 或者:手动传入参数
|
|
127
127
|
llm = BaseAPI(
|
|
128
128
|
api_key="your-api-key",
|
|
129
|
-
base_url="https://api.openai.com/v1
|
|
129
|
+
base_url="https://api.openai.com/v1",
|
|
130
130
|
model="gpt-4o"
|
|
131
131
|
)
|
|
132
132
|
```
|
|
@@ -134,11 +134,11 @@ llm = BaseAPI(
|
|
|
134
134
|
`tina.env` 文件示例:
|
|
135
135
|
```env
|
|
136
136
|
LLM_API_KEY="your-api-key"
|
|
137
|
-
BASE_URL="https://api.openai.com/v1
|
|
137
|
+
BASE_URL="https://api.openai.com/v1"
|
|
138
138
|
MODEL_NAME="gpt-4o"
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
-
>
|
|
141
|
+
> **base_url 规则(0.7.0 起)**:只写服务根地址即可(如 `https://api.openai.com/v1`),tina 会自动补上 `/chat/completions`;写完整地址(`.../chat/completions`)也依然兼容。旧文档要求"必须自带 `/chat/completions`"的说法已作废。
|
|
142
142
|
|
|
143
143
|
### 1.2 非流式调用
|
|
144
144
|
|
|
@@ -864,55 +864,7 @@ message = build_multimodal_message(
|
|
|
864
864
|
|
|
865
865
|
tina 提供了一些开箱即用的工具函数和工具包,帮助你快速搭建应用。
|
|
866
866
|
|
|
867
|
-
### 6.1
|
|
868
|
-
|
|
869
|
-
tina 自带一套系统工具包,包含文件操作、代码执行等常用功能:
|
|
870
|
-
|
|
871
|
-
```python
|
|
872
|
-
from tina import Agent, Tools
|
|
873
|
-
from tina.llm import BaseAPI
|
|
874
|
-
from tina.utils.system_tools import system_tools
|
|
875
|
-
|
|
876
|
-
tools = Tools(name="my_tools")
|
|
877
|
-
tools += system_tools # 添加 tina 自带的系统工具包(工具集需命名)
|
|
878
|
-
|
|
879
|
-
agent = Agent(
|
|
880
|
-
llm=BaseAPI(),
|
|
881
|
-
tools=tools,
|
|
882
|
-
system_prompt="你是一个系统助手,可以帮助我管理文件和执行代码"
|
|
883
|
-
)
|
|
884
|
-
|
|
885
|
-
result = agent.predict(instruction="帮我看看当前目录下有哪些文件", stream=True)
|
|
886
|
-
for chunk in result:
|
|
887
|
-
print(chunk.content, end="")
|
|
888
|
-
```
|
|
889
|
-
|
|
890
|
-
**内置工具一览:**
|
|
891
|
-
|
|
892
|
-
| 工具名称 | 需要确认 | 功能说明 |
|
|
893
|
-
|---------|---------|---------|
|
|
894
|
-
| `get_time` | ❌ | 获取当前系统时间 |
|
|
895
|
-
| `list_dir` | ❌ | 列出目录下的文件和子目录 |
|
|
896
|
-
| `project_tree` | ❌ | 获取项目目录结构(类似 tree 命令) |
|
|
897
|
-
| `get_path` | ❌ | 获取文件/文件夹的绝对路径 |
|
|
898
|
-
| `read_code` | ❌ | 按字符范围读取文件内容片段 |
|
|
899
|
-
| `read_code_by_line` | ❌ | 按行读取代码片段(带行号) |
|
|
900
|
-
| `search_in_files` | ❌ | 在项目中按正则搜索文本(自动忽略 `.git`/`.venv` 等) |
|
|
901
|
-
| `delay` | ❌ | 延时函数 |
|
|
902
|
-
| `make_dir` | ✅ | 创建目录(自动创建父目录) |
|
|
903
|
-
| `write_code` | ✅ | 写入文件内容(覆盖,自动创建父目录) |
|
|
904
|
-
| `append_code` | ✅ | 追加写入文件内容(自动创建父目录) |
|
|
905
|
-
| `delete_path` | ✅ | 删除文件或目录(`recursive=True` 可递归) |
|
|
906
|
-
| `replace_code_by_lines` | ✅ | 按行范围替换代码块 |
|
|
907
|
-
| `terminal` | ✅ | 在终端运行指令(带超时) |
|
|
908
|
-
| `run_python` | ✅ | 执行一小段 Python 代码 |
|
|
909
|
-
| `shot_down_system` | ✅ | 关机 |
|
|
910
|
-
|
|
911
|
-
> `需要确认` 的工具在执行时会触发 `on_tool_confirmation` 事件,适合接入人工审批流程。
|
|
912
|
-
>
|
|
913
|
-
> 由于系统工具包使用了命名空间,工具在模型侧的实际名称为 `tina_sys_tools_{名称}`,例如 `tina_sys_tools_read_code`。
|
|
914
|
-
|
|
915
|
-
### 6.2 后台工作器 `AgentWorker`
|
|
867
|
+
### 6.1 后台工作器 `AgentWorker`
|
|
916
868
|
|
|
917
869
|
`AgentWorker` 将 Agent 包装为异步后台服务,通过消息队列接收外部指令并持续处理:
|
|
918
870
|
|
|
@@ -952,7 +904,7 @@ asyncio.run(main())
|
|
|
952
904
|
|
|
953
905
|
`AgentWorker` 还会将自身的 `put` 方法自动注册为 Agent 的工具,方便多 Agent 场景下互相调用。
|
|
954
906
|
|
|
955
|
-
### 6.
|
|
907
|
+
### 6.2 终端交互控制台 `run_agent_in_cli`
|
|
956
908
|
|
|
957
909
|
快速启动一个 Agent 交互式终端,适合调试和测试:
|
|
958
910
|
|
|
@@ -978,7 +930,7 @@ run_agent_in_cli(agent)
|
|
|
978
930
|
| `#clear` | 清屏 |
|
|
979
931
|
| `exit` / `quit` | 退出对话(`#exit` 不支持,会被当作普通输入) |
|
|
980
932
|
|
|
981
|
-
### 6.
|
|
933
|
+
### 6.3 多模态消息构建器 `build_multimodal_message`
|
|
982
934
|
|
|
983
935
|
用于灵活构建包含多模态内容的消息:
|
|
984
936
|
|
|
@@ -1001,7 +953,7 @@ print(message)
|
|
|
1001
953
|
|
|
1002
954
|
## 七、拓展包(可选)
|
|
1003
955
|
|
|
1004
|
-
|
|
956
|
+
除核心之外的可选能力:有**随主包提供**的(编码工具),也有拆成**独立发行包**的(终端界面、多 Agent 环境),按需安装、可独立更新与发布。主包内不再包含后者的实现(仅保留 `tina.utils.*` 兼容转发壳)。
|
|
1005
957
|
|
|
1006
958
|
### 7.1 终端界面 TUI(`tina-tui`)
|
|
1007
959
|
|
|
@@ -1011,6 +963,21 @@ tina 核心保持轻量:终端界面与多 Agent 环境这两块较大的功
|
|
|
1011
963
|
pip install tina-python[tui] # 等价于安装 tina-tui
|
|
1012
964
|
```
|
|
1013
965
|
|
|
966
|
+
**开箱即用的 `tinacode` 命令**:装好后可以在任意目录直接起一个编码 agent,不用写 Python:
|
|
967
|
+
|
|
968
|
+
```bash
|
|
969
|
+
cd <你的项目>
|
|
970
|
+
tinacode
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
- 工作目录 = 你敲命令时所在的目录(`code_*` 工具的相对路径以它为准)
|
|
974
|
+
- 会话历史存到 `<cwd>/.tina/chat_sessions/`,**按目录隔离**
|
|
975
|
+
- 模型配置读 `<cwd>/tina.env` 或 `.env`,没有则回退全局 `~/.tina/tina.env`
|
|
976
|
+
- 目录里的 `.tinacode.md` / `AGENTS.md` / `.tina.md` 自动注入系统提示(目录级定制不用改代码)
|
|
977
|
+
- 工具集是 `CodingTools`(见 [7.3](#73-编码工具codingtools))
|
|
978
|
+
|
|
979
|
+
自己组装 Agent 再交给 TUI:
|
|
980
|
+
|
|
1014
981
|
```python
|
|
1015
982
|
from tina import Agent, Tools
|
|
1016
983
|
from tina.llm import BaseAPI
|
|
@@ -1031,8 +998,9 @@ run_agent_in_tui(agent, max_tokens=32000)
|
|
|
1031
998
|
- 自动为 Agent 注册工具确认事件(`require_confirmation=True` 的工具会弹出选择条)
|
|
1032
999
|
- 上下文 token 占用与上限进度(显示百分比,≥80% 变黄、超限变红警告),运行时显示动画
|
|
1033
1000
|
- `Esc` 可打断本轮回复;已生成的部分正文写回上下文,进行中的工具调用记为「该次调用被打断」
|
|
1034
|
-
- 输入框支持多行与粘贴;`Enter` 发送、`Shift+Enter` 换行、`Tab`
|
|
1001
|
+
- 输入框支持多行与粘贴;`Enter` 发送、`Shift+Enter` 换行、`Tab` 补全命令与会话 id
|
|
1035
1002
|
- 底部粘性滚动:在底部时自动跟随输出,向上滚动查看历史时不会被打扰,滚回底部自动恢复
|
|
1003
|
+
- 会话自动归档到 `<项目>/.tina/chat_sessions/`:可切换 / 重命名 / 删除,首轮结束后自动起名
|
|
1036
1004
|
- 可选 `unlimited_context=True`:用 tina 提供的无限制上下文管理器替换 Agent 的(不裁剪历史、不截断工具结果)
|
|
1037
1005
|
|
|
1038
1006
|
| 指令 | 功能 |
|
|
@@ -1042,6 +1010,11 @@ run_agent_in_tui(agent, max_tokens=32000)
|
|
|
1042
1010
|
| `#context` | 查看当前上下文 |
|
|
1043
1011
|
| `#model` | 查看当前模型信息 |
|
|
1044
1012
|
| `#tokens` | 查看当前上下文 token 占用 |
|
|
1013
|
+
| `#sessions` | 列出已保存的会话(可跟关键字过滤) |
|
|
1014
|
+
| `#switch` | 切换会话(按 id / id 前缀 / 标题) |
|
|
1015
|
+
| `#new` | 新建会话(当前会话自动保存) |
|
|
1016
|
+
| `#rename` | 重命名当前会话 |
|
|
1017
|
+
| `#delete` | 删除会话 |
|
|
1045
1018
|
| `#compact` | 压缩上下文(让 Agent 自我总结并并入 system) |
|
|
1046
1019
|
| `#clear` | 清空上下文与界面 |
|
|
1047
1020
|
| `#exit` | 退出 |
|
|
@@ -1081,6 +1054,42 @@ MultiAgentWeb(env, port=7077).run()
|
|
|
1081
1054
|
|
|
1082
1055
|
> 兼容提示:旧路径 `tina.utils.multi_agent` 仍可用(主包内保留转发壳);未安装 `tina-multi-agent` 时会提示安装。
|
|
1083
1056
|
|
|
1057
|
+
### 7.3 编码工具(`CodingTools`)
|
|
1058
|
+
|
|
1059
|
+
面向「写代码」的**主包内置**能力(命名空间 `code`),像普通工具包一样按需搭配到任意 Agent:一个编码工具包 + 一个项目感知的上下文管理器。提供可靠的**局部编辑**(精确文本匹配 + 唯一性校验 + 原子写)、搜索增强与命令输出截断。
|
|
1060
|
+
|
|
1061
|
+
```python
|
|
1062
|
+
from tina import Agent
|
|
1063
|
+
from tina.utils.coding_tools import CodingTools
|
|
1064
|
+
|
|
1065
|
+
tools = CodingTools(root=".").get_tools() # code_read / code_glob / code_grep / code_write / code_edit / code_patch / code_bash
|
|
1066
|
+
agent = Agent(llm=llm, tools=tools)
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
| 工具 | 说明 | 需确认 |
|
|
1070
|
+
|------|------|--------|
|
|
1071
|
+
| `code_read` | 按行读取(offset/limit、行号、总行数与截断提示) | 否 |
|
|
1072
|
+
| `code_glob` | 按 glob 查找文件(如 `**/*.py`) | 否 |
|
|
1073
|
+
| `code_grep` | 正则搜索(`include` / 上下文行 / 忽略大小写) | 否 |
|
|
1074
|
+
| `code_write` | 整文件写入(`.py` 写前语法校验) | ✅ |
|
|
1075
|
+
| `code_edit` | 精确文本替换(命中多次需 `replace_all`,返回 diff) | ✅ |
|
|
1076
|
+
| `code_patch` | 应用 unified diff 补丁(一次多处/跨行改动,行号可偏差、上下文对不上则整体中止) | ✅ |
|
|
1077
|
+
| `code_bash` | 执行命令(首尾截断、带 exit code) | ✅ |
|
|
1078
|
+
|
|
1079
|
+
配套的项目感知上下文管理器(自动注入 `AGENTS.md` / `.tinacode.md` / `.tina.md`、工作目录与目录结构摘要,可用 `refresh_project_context()` 刷新):
|
|
1080
|
+
|
|
1081
|
+
既可在构造时传入,也可之后替换:
|
|
1082
|
+
|
|
1083
|
+
```python
|
|
1084
|
+
from tina import Agent
|
|
1085
|
+
from tina.utils.coding_context import CodingContextManager
|
|
1086
|
+
|
|
1087
|
+
agent = Agent(llm=llm, tools=tools, context_manager=CodingContextManager(root="."))
|
|
1088
|
+
# 或:agent.set_context_manager(CodingContextManager(root="."))
|
|
1089
|
+
```
|
|
1090
|
+
|
|
1091
|
+
> 未显式传 `system_prompt` 时,Agent 会**保留** `context_manager` 自带的系统提示(不再用默认提示覆盖);显式传 `system_prompt` 才会覆盖它。
|
|
1092
|
+
|
|
1084
1093
|
---
|
|
1085
1094
|
|
|
1086
1095
|
## 附录
|
|
@@ -1091,7 +1100,7 @@ tina 支持通过环境文件配置 API 信息,自动从当前目录查找 `.e
|
|
|
1091
1100
|
|
|
1092
1101
|
```env
|
|
1093
1102
|
LLM_API_KEY="your-api-key"
|
|
1094
|
-
BASE_URL="https://api.openai.com/v1
|
|
1103
|
+
BASE_URL="https://api.openai.com/v1"
|
|
1095
1104
|
MODEL_NAME="gpt-4o"
|
|
1096
1105
|
MAX_INPUT=8000
|
|
1097
1106
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tina-python"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.2"
|
|
8
8
|
description = "tina is in your computer!"
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -29,7 +29,9 @@ GitHub = "https://github.com/XIMOCY/tina.git"
|
|
|
29
29
|
|
|
30
30
|
[project.optional-dependencies]
|
|
31
31
|
tui = [
|
|
32
|
-
|
|
32
|
+
# 0.2.0 起提供 tinacode 命令;不收紧的话,已装 tina-tui 0.1.0 的环境
|
|
33
|
+
# pip 不会升级它,用户拿不到 tinacode
|
|
34
|
+
"tina-tui>=0.2.0",
|
|
33
35
|
]
|
|
34
36
|
multi-agent = [
|
|
35
37
|
"tina-multi-agent>=0.1.0",
|
|
@@ -43,7 +45,7 @@ test = [
|
|
|
43
45
|
"pytest-cov>=7.0",
|
|
44
46
|
]
|
|
45
47
|
all = [
|
|
46
|
-
"tina-tui>=0.
|
|
48
|
+
"tina-tui>=0.2.0",
|
|
47
49
|
"tina-multi-agent>=0.1.0",
|
|
48
50
|
"mcp>=2.0",
|
|
49
51
|
]
|
|
@@ -106,7 +106,9 @@ class Agent:
|
|
|
106
106
|
self.events = AgentEvents() if events is None else events
|
|
107
107
|
if system_prompt is not None:
|
|
108
108
|
self.context_manager.set_system_message(system_prompt)
|
|
109
|
-
|
|
109
|
+
elif not self.context_manager.get_system_message():
|
|
110
|
+
# 未显式给 system_prompt 时,保留传入的 context_manager 自带的系统提示;
|
|
111
|
+
# 只有它没有系统提示时才填默认。
|
|
110
112
|
self.context_manager.set_system_message(Prompt("tina").prompt)
|
|
111
113
|
self._inject_keyword_actions_prompt()
|
|
112
114
|
|
|
@@ -362,6 +364,26 @@ class Agent:
|
|
|
362
364
|
except Exception as e:
|
|
363
365
|
raise e
|
|
364
366
|
|
|
367
|
+
def refresh_mcp_tools(self) -> None:
|
|
368
|
+
"""按当前 MCP 连接重新合并工具(新增 / 移除 server 后调用)
|
|
369
|
+
|
|
370
|
+
``add_mcp_server`` / ``remove_mcp_server`` 会调用它;这样动态增删的 MCP
|
|
371
|
+
服务其工具才会真正进入工具集(既可被模型调用,也能在 TUI 的 `#tools` 看到)。
|
|
372
|
+
"""
|
|
373
|
+
if self.mcp_client is None:
|
|
374
|
+
return
|
|
375
|
+
try:
|
|
376
|
+
new_tools = self.mcp_client.to_tina_tools()
|
|
377
|
+
except Exception: # noqa: BLE001 连接异常时不打断
|
|
378
|
+
return
|
|
379
|
+
subs = getattr(self.tools, "_sub_bundles", None)
|
|
380
|
+
if subs is not None:
|
|
381
|
+
subs[:] = [b for b in subs if b.instance_name != "mcp"]
|
|
382
|
+
try:
|
|
383
|
+
self.tools.add_tools(new_tools)
|
|
384
|
+
except Exception: # noqa: BLE001 工具集未命名等情况下静默跳过
|
|
385
|
+
pass
|
|
386
|
+
|
|
365
387
|
def get_messages(self) -> list:
|
|
366
388
|
"""
|
|
367
389
|
获取当前Agent的完整消息列表(包含 system 系统提示词)
|
|
@@ -541,7 +563,7 @@ class Agent:
|
|
|
541
563
|
timeout:超时时间
|
|
542
564
|
"""
|
|
543
565
|
if self.mcp_client is not None:
|
|
544
|
-
|
|
566
|
+
ok = self.mcp_client.add_server(
|
|
545
567
|
server_id,
|
|
546
568
|
type=type,
|
|
547
569
|
command=command,
|
|
@@ -552,6 +574,8 @@ class Agent:
|
|
|
552
574
|
max_retries=max_retries,
|
|
553
575
|
timeout=timeout,
|
|
554
576
|
)
|
|
577
|
+
self.refresh_mcp_tools()
|
|
578
|
+
return ok
|
|
555
579
|
else:
|
|
556
580
|
raise ValueError("MCP客户端未初始化,请先初始化MCP客户端")
|
|
557
581
|
|
|
@@ -562,7 +586,9 @@ class Agent:
|
|
|
562
586
|
server_id:服务器ID
|
|
563
587
|
"""
|
|
564
588
|
if self.mcp_client is not None:
|
|
565
|
-
|
|
589
|
+
ok = self.mcp_client.remove_server(server_id)
|
|
590
|
+
self.refresh_mcp_tools()
|
|
591
|
+
return ok
|
|
566
592
|
else:
|
|
567
593
|
raise ValueError("MCP客户端未初始化,请先初始化MCP客户端")
|
|
568
594
|
|
|
@@ -162,7 +162,7 @@ class Tools:
|
|
|
162
162
|
|
|
163
163
|
def __init__(
|
|
164
164
|
self,
|
|
165
|
-
tools_executor: ToolsExecutor =
|
|
165
|
+
tools_executor: ToolsExecutor|None = None,
|
|
166
166
|
name: str = None,
|
|
167
167
|
metadata: dict = None,
|
|
168
168
|
):
|
|
@@ -176,7 +176,10 @@ class Tools:
|
|
|
176
176
|
self._direct_tools = []
|
|
177
177
|
self._sub_bundles = []
|
|
178
178
|
self.disable_tools = {}
|
|
179
|
-
|
|
179
|
+
if tools_executor is None:
|
|
180
|
+
self.tools_executor = ToolsExecutor()
|
|
181
|
+
else:
|
|
182
|
+
self.tools_executor = tools_executor
|
|
180
183
|
self.instance_name = name
|
|
181
184
|
self.metadata = metadata
|
|
182
185
|
|
|
@@ -101,7 +101,9 @@ class MultimodalAgent(Agent):
|
|
|
101
101
|
self.events = AgentEvents() if events is None else events
|
|
102
102
|
if system_prompt is not None:
|
|
103
103
|
self.context_manager.set_system_message(system_prompt)
|
|
104
|
-
|
|
104
|
+
elif not self.context_manager.get_system_message():
|
|
105
|
+
# 未显式给 system_prompt 时,保留传入的 context_manager 自带的系统提示;
|
|
106
|
+
# 只有它没有系统提示时才填默认。
|
|
105
107
|
self.context_manager.set_system_message(Prompt("tina").prompt)
|
|
106
108
|
self._inject_keyword_actions_prompt()
|
|
107
109
|
# 初始化消息,可以直接使用context_manager来修改messages
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from .base_api import BaseAPI
|
|
2
2
|
from .base_multimodal_api import BaseMultimodalAPI
|
|
3
|
-
from .files_api import FilesAPI
|
|
3
|
+
from .files_api import FilesAPI
|
|
4
4
|
|
|
5
5
|
__all__ = [
|
|
6
6
|
# 基础类
|
|
@@ -8,5 +8,4 @@ __all__ = [
|
|
|
8
8
|
"BaseMultimodalAPI",
|
|
9
9
|
# 文件接口
|
|
10
10
|
"FilesAPI",
|
|
11
|
-
"is_file_id",
|
|
12
11
|
]
|
|
@@ -140,6 +140,34 @@ class BaseAPI:
|
|
|
140
140
|
self.logger.debug(f"BaseAPI - 异步客户端已在当前 Loop 中创建")
|
|
141
141
|
return self._async_client
|
|
142
142
|
|
|
143
|
+
async def fetch_balance(self) -> dict | None:
|
|
144
|
+
"""查询账户余额,返回服务端的原始 JSON;不支持或失败时返回 None
|
|
145
|
+
|
|
146
|
+
这是 DeepSeek 风格的 ``GET /user/balance``,不属于 OpenAI 标准接口——
|
|
147
|
+
其它服务端多半返回 404,此时返回 None,调用方据此优雅降级。
|
|
148
|
+
key 只在本层使用,不对外暴露(``self.api_key`` 一直是掩码)。
|
|
149
|
+
"""
|
|
150
|
+
root = derive_api_root(self.base_url)
|
|
151
|
+
key = super().__getattribute__("_BaseAPI__api_key")
|
|
152
|
+
if not root or not key:
|
|
153
|
+
return None
|
|
154
|
+
try:
|
|
155
|
+
response = await self.aclient.get(
|
|
156
|
+
f"{root}/user/balance",
|
|
157
|
+
headers={"Authorization": f"Bearer {key}"},
|
|
158
|
+
timeout=10,
|
|
159
|
+
)
|
|
160
|
+
if response.status_code != 200:
|
|
161
|
+
self.logger.debug(
|
|
162
|
+
f"BaseAPI - 余额查询不可用:HTTP {response.status_code}"
|
|
163
|
+
)
|
|
164
|
+
return None
|
|
165
|
+
data = response.json()
|
|
166
|
+
except Exception as error: # noqa: BLE001 查余额失败不该影响聊天
|
|
167
|
+
self.logger.debug(f"BaseAPI - 余额查询失败: {error}")
|
|
168
|
+
return None
|
|
169
|
+
return data if isinstance(data, dict) else None
|
|
170
|
+
|
|
143
171
|
def __repr__(self):
|
|
144
172
|
return f"<BaseAPI model={self.model} base url={self.base_url}>"
|
|
145
173
|
|
|
@@ -28,11 +28,8 @@ import httpx
|
|
|
28
28
|
from ..core import logger
|
|
29
29
|
from ..core.error import APIRequestFailed
|
|
30
30
|
from ..utils.env_reader import EnvReader
|
|
31
|
-
from ..utils.url import derive_api_root
|
|
32
31
|
|
|
33
32
|
|
|
34
|
-
# file_id 前缀(DeepSeek 形如 file-api-0a1b2c...)
|
|
35
|
-
FILE_ID_PREFIX = "file-api-"
|
|
36
33
|
|
|
37
34
|
# 支持的图片扩展名 -> MIME(官方仅支持 JPEG / PNG / GIF / WebP)
|
|
38
35
|
SUPPORTED_EXTENSIONS = {
|
|
@@ -53,9 +50,19 @@ DEFAULT_CACHE_FILENAME = "files_cache.json"
|
|
|
53
50
|
CACHE_EXPIRY_MARGIN_SECONDS = 60 # 快过期时提前重传
|
|
54
51
|
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _derive_root(base_url: str) -> str:
|
|
57
|
+
"""从 base_url 推导 Files API 的根地址
|
|
58
|
+
"""
|
|
59
|
+
if not base_url or not isinstance(base_url, str):
|
|
60
|
+
raise ValueError("base_url 不能为空")
|
|
61
|
+
root = base_url.rstrip("/")
|
|
62
|
+
suffix = "/chat/completions"
|
|
63
|
+
if root.endswith(suffix):
|
|
64
|
+
root = root[: -len(suffix)]
|
|
65
|
+
return root.rstrip("/")
|
|
59
66
|
|
|
60
67
|
|
|
61
68
|
def _default_cache_path() -> str:
|
|
@@ -172,7 +179,7 @@ class FilesAPI:
|
|
|
172
179
|
"FilesAPI - 未找到 Base URL,请通过参数 base_url 传入或创建 .env 文件并设置 base_url"
|
|
173
180
|
)
|
|
174
181
|
|
|
175
|
-
self.root =
|
|
182
|
+
self.root = _derive_root(self.base_url)
|
|
176
183
|
self.files_url = f"{self.root}/files"
|
|
177
184
|
|
|
178
185
|
self.use_cache = use_cache
|