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.
Files changed (62) hide show
  1. {tina_python-0.7.1/tina_python.egg-info → tina_python-0.7.2}/PKG-INFO +70 -61
  2. {tina_python-0.7.1 → tina_python-0.7.2}/README.md +67 -58
  3. {tina_python-0.7.1 → tina_python-0.7.2}/pyproject.toml +5 -3
  4. {tina_python-0.7.1 → tina_python-0.7.2}/tina/__init__.py +1 -1
  5. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/agent.py +29 -3
  6. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/tools.py +5 -2
  7. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/multimodal_agent.py +3 -1
  8. {tina_python-0.7.1 → tina_python-0.7.2}/tina/llm/__init__.py +1 -2
  9. {tina_python-0.7.1 → tina_python-0.7.2}/tina/llm/base_api.py +28 -0
  10. {tina_python-0.7.1 → tina_python-0.7.2}/tina/llm/files_api.py +14 -7
  11. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/__init__.py +4 -0
  12. tina_python-0.7.2/tina/utils/coding_context.py +253 -0
  13. tina_python-0.7.2/tina/utils/coding_tools.py +689 -0
  14. tina_python-0.7.2/tina/utils/session_store.py +331 -0
  15. {tina_python-0.7.1 → tina_python-0.7.2/tina_python.egg-info}/PKG-INFO +70 -61
  16. {tina_python-0.7.1 → tina_python-0.7.2}/tina_python.egg-info/SOURCES.txt +3 -1
  17. {tina_python-0.7.1 → tina_python-0.7.2}/tina_python.egg-info/requires.txt +2 -2
  18. tina_python-0.7.1/tina/utils/system_tools.py +0 -547
  19. {tina_python-0.7.1 → tina_python-0.7.2}/LICENSE +0 -0
  20. {tina_python-0.7.1 → tina_python-0.7.2}/MANIFEST.in +0 -0
  21. {tina_python-0.7.1 → tina_python-0.7.2}/setup.cfg +0 -0
  22. {tina_python-0.7.1 → tina_python-0.7.2}/setup.py +0 -0
  23. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/__init__.py +0 -0
  24. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/__init__.py +0 -0
  25. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/agent_response.py +0 -0
  26. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/agent_runtime.py +0 -0
  27. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/context_manager.py +0 -0
  28. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/events.py +0 -0
  29. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/executor.py +0 -0
  30. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/keyword_actions.py +0 -0
  31. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/prompt.py +0 -0
  32. {tina_python-0.7.1 → tina_python-0.7.2}/tina/agent/core/state.py +0 -0
  33. {tina_python-0.7.1 → tina_python-0.7.2}/tina/core/__init__.py +0 -0
  34. {tina_python-0.7.1 → tina_python-0.7.2}/tina/core/error.py +0 -0
  35. {tina_python-0.7.1 → tina_python-0.7.2}/tina/core/logger.py +0 -0
  36. {tina_python-0.7.1 → tina_python-0.7.2}/tina/llm/base_multimodal_api.py +0 -0
  37. {tina_python-0.7.1 → tina_python-0.7.2}/tina/mcp/__init__.py +0 -0
  38. {tina_python-0.7.1 → tina_python-0.7.2}/tina/mcp/client.py +0 -0
  39. {tina_python-0.7.1 → tina_python-0.7.2}/tina/mcp/mcp_tools_executor.py +0 -0
  40. {tina_python-0.7.1 → tina_python-0.7.2}/tina/py.typed +0 -0
  41. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/agent_worker.py +0 -0
  42. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/deepseek.py +0 -0
  43. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/doc_parser.py +0 -0
  44. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/env_reader.py +0 -0
  45. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/__init__.py +0 -0
  46. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/environment.py +0 -0
  47. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/message.py +0 -0
  48. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/message_bus.py +0 -0
  49. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/web/__init__.py +0 -0
  50. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multi_agent/web/server.py +0 -0
  51. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/multimodal_formatter.py +0 -0
  52. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/output_parser.py +0 -0
  53. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/run_agent_in_cli.py +0 -0
  54. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/tui/__init__.py +0 -0
  55. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/tui/context_manager.py +0 -0
  56. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/tui/token.py +0 -0
  57. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/tui/tui.py +0 -0
  58. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/type_mapper.py +0 -0
  59. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/url.py +0 -0
  60. {tina_python-0.7.1 → tina_python-0.7.2}/tina/utils/usage.py +0 -0
  61. {tina_python-0.7.1 → tina_python-0.7.2}/tina_python.egg-info/dependency_links.txt +0 -0
  62. {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.1
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.1.0; extra == "tui"
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.1.0; extra == "all"
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/chat/completions",
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/chat/completions",
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/chat/completions"
175
+ BASE_URL="https://api.openai.com/v1"
176
176
  MODEL_NAME="gpt-4o"
177
177
  ```
178
178
 
179
- > **注意**:`base_url` 需要包含完整的 `/chat/completions` 路由,tina 不会自动补充。
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 系统工具包 `system_tools`
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.3 终端交互控制台 `run_agent_in_cli`
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.4 多模态消息构建器 `build_multimodal_message`
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
- tina 核心保持轻量:终端界面与多 Agent 环境这两块较大的功能,拆成**独立发行包**,按需安装、独立更新与发布。主包内不再包含它们的实现(仅保留 `tina.utils.*` 兼容转发壳)。
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/chat/completions"
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/chat/completions",
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/chat/completions",
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/chat/completions"
137
+ BASE_URL="https://api.openai.com/v1"
138
138
  MODEL_NAME="gpt-4o"
139
139
  ```
140
140
 
141
- > **注意**:`base_url` 需要包含完整的 `/chat/completions` 路由,tina 不会自动补充。
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 系统工具包 `system_tools`
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.3 终端交互控制台 `run_agent_in_cli`
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.4 多模态消息构建器 `build_multimodal_message`
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
- tina 核心保持轻量:终端界面与多 Agent 环境这两块较大的功能,拆成**独立发行包**,按需安装、独立更新与发布。主包内不再包含它们的实现(仅保留 `tina.utils.*` 兼容转发壳)。
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/chat/completions"
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.1"
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
- "tina-tui>=0.1.0",
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.1.0",
48
+ "tina-tui>=0.2.0",
47
49
  "tina-multi-agent>=0.1.0",
48
50
  "mcp>=2.0",
49
51
  ]
@@ -21,4 +21,4 @@ __all__ = [
21
21
  "AgentEvents",
22
22
  "FilesAPI",
23
23
  ]
24
- __version__ = "0.7.1"
24
+ __version__ = "0.7.2"
@@ -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
- else:
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
- return self.mcp_client.add_server(
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
- return self.mcp_client.remove_server(server_id)
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 = 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
- self.tools_executor = tools_executor
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
- else:
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, is_file_id
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
- def is_file_id(value: Any) -> bool:
57
- """判断是否为 Files API 的 file_id(``file-api-...``)"""
58
- return isinstance(value, str) and value.startswith(FILE_ID_PREFIX)
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 = derive_api_root(self.base_url)
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