tketool.llm 1.3.4__py3-none-any.whl

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 (122) hide show
  1. tketool/llm/__init__.py +7 -0
  2. tketool/lmc/__init__.py +5 -0
  3. tketool/lmc/agent_framework/__init__.py +5 -0
  4. tketool/lmc/agent_framework/mcp_tools/__init__.py +4 -0
  5. tketool/lmc/agent_framework/mcp_tools/demo_tools.py +35 -0
  6. tketool/lmc/agent_framework/mcp_tools/function_handler.py +224 -0
  7. tketool/lmc/agent_framework/mcp_tools/interfaces.py +91 -0
  8. tketool/lmc/agent_framework/mcp_tools/registry.py +76 -0
  9. tketool/lmc/agent_framework/mcp_tools/simple_code.py +73 -0
  10. tketool/lmc/agent_framework/mcp_tools/tool_types.py +122 -0
  11. tketool/lmc/agent_framework/memory/__init__.py +2 -0
  12. tketool/lmc/agent_framework/memory/interfaces.py +71 -0
  13. tketool/lmc/agent_framework/memory/local_memory.py +160 -0
  14. tketool/lmc/agent_framework/memory/memory_imps/__init__.py +49 -0
  15. tketool/lmc/agent_framework/memory/memory_imps/hindsight_like.py +532 -0
  16. tketool/lmc/agent_framework/memory/memory_imps/ml2_indexes.py +25 -0
  17. tketool/lmc/agent_framework/memory/storage_extensions/__init__.py +43 -0
  18. tketool/lmc/agent_framework/memory/storage_extensions/in_memory_bank_storage.py +25 -0
  19. tketool/lmc/agent_framework/memory/storage_extensions/in_memory_entity_index.py +61 -0
  20. tketool/lmc/agent_framework/memory/storage_extensions/in_memory_sparse_index.py +32 -0
  21. tketool/lmc/agent_framework/memory/storage_extensions/in_memory_temporal_index.py +28 -0
  22. tketool/lmc/agent_framework/memory/storage_extensions/in_memory_vector_index.py +34 -0
  23. tketool/lmc/agent_framework/memory/storage_extensions/ml2_bank_storage.py +90 -0
  24. tketool/lmc/agent_framework/memory/storage_extensions/ml2_entity_index.py +73 -0
  25. tketool/lmc/agent_framework/memory/storage_extensions/ml2_sparse_index.py +41 -0
  26. tketool/lmc/agent_framework/memory/storage_extensions/ml2_temporal_index.py +35 -0
  27. tketool/lmc/agent_framework/memory/storage_extensions/ml2_vector_index.py +44 -0
  28. tketool/lmc/agent_framework/memory/types.py +239 -0
  29. tketool/lmc/agent_framework/observer/__init__.py +13 -0
  30. tketool/lmc/agent_framework/observer/observer.py +322 -0
  31. tketool/lmc/agent_framework/observer/redactor.py +68 -0
  32. tketool/lmc/agent_framework/observer/report.py +67 -0
  33. tketool/lmc/agent_framework/observer/sink.py +57 -0
  34. tketool/lmc/agent_framework/observer/types.py +74 -0
  35. tketool/lmc/agent_framework/scheduler2/__init__.py +4 -0
  36. tketool/lmc/agent_framework/scheduler2/base.py +32 -0
  37. tketool/lmc/agent_framework/scheduler2/chains/__init__.py +4 -0
  38. tketool/lmc/agent_framework/scheduler2/chains/base.py +492 -0
  39. tketool/lmc/agent_framework/scheduler2/chains/main.py +674 -0
  40. tketool/lmc/agent_framework/scheduler2/chains/plan_main.py +368 -0
  41. tketool/lmc/agent_framework/scheduler2/chains/tool_call.py +461 -0
  42. tketool/lmc/agent_framework/scheduler2/graph.py +19 -0
  43. tketool/lmc/agent_framework/scheduler2/memory_kit/__init__.py +35 -0
  44. tketool/lmc/agent_framework/scheduler2/memory_kit/common.py +47 -0
  45. tketool/lmc/agent_framework/scheduler2/memory_kit/main_chain_memory.py +82 -0
  46. tketool/lmc/agent_framework/scheduler2/memory_kit/tool_call_memory.py +214 -0
  47. tketool/lmc/agent_framework/scheduler2/node_types.py +12 -0
  48. tketool/lmc/agent_framework/scheduler2/nodes/__init__.py +21 -0
  49. tketool/lmc/agent_framework/scheduler2/nodes/common.py +5 -0
  50. tketool/lmc/agent_framework/scheduler2/nodes/decision.py +25 -0
  51. tketool/lmc/agent_framework/scheduler2/nodes/info_summary.py +15 -0
  52. tketool/lmc/agent_framework/scheduler2/nodes/main_chain/__init__.py +3 -0
  53. tketool/lmc/agent_framework/scheduler2/nodes/main_chain/experience.py +87 -0
  54. tketool/lmc/agent_framework/scheduler2/nodes/main_chain/finalize.py +83 -0
  55. tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/__init__.py +9 -0
  56. tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_build.py +125 -0
  57. tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_check.py +60 -0
  58. tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_select.py +56 -0
  59. tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_synthesize.py +101 -0
  60. tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_types.py +60 -0
  61. tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_update.py +71 -0
  62. tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/subtask_run.py +77 -0
  63. tketool/lmc/agent_framework/scheduler2/nodes/task_identify.py +133 -0
  64. tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/__init__.py +5 -0
  65. tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/parameter_generate.py +134 -0
  66. tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_call.py +109 -0
  67. tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_decision.py +128 -0
  68. tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_experience_write.py +81 -0
  69. tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_result_verify.py +99 -0
  70. tketool/lmc/agent_framework/scheduler2/nodes/verify.py +135 -0
  71. tketool/lmc/agent_framework/scheduler2/prompting.py +126 -0
  72. tketool/lmc/agent_framework/scheduler2/types.py +194 -0
  73. tketool/lmc/embeddings.py +17 -0
  74. tketool/lmc/llms/__init__.py +1 -0
  75. tketool/lmc/llms/embeddings.py +215 -0
  76. tketool/lmc/llms/openai.py +326 -0
  77. tketool/lmc/lmc_linked.py +604 -0
  78. tketool/lmc/lmc_linked_flow.py +7 -0
  79. tketool/lmc/lmc_prompt_invoker.py +426 -0
  80. tketool/lmc/models.py +97 -0
  81. tketool/lmc/prompts/__init__.py +0 -0
  82. tketool/lmc/prompts/prompt_controller.py +462 -0
  83. tketool/lmc/prompts/templates/agent_scheduler/auto_repair.txt +38 -0
  84. tketool/lmc/prompts/templates/agent_scheduler/context_compact.txt +41 -0
  85. tketool/lmc/prompts/templates/agent_scheduler/context_resolve_reference.txt +42 -0
  86. tketool/lmc/prompts/templates/agent_scheduler/decompose_task_plan.txt +71 -0
  87. tketool/lmc/prompts/templates/agent_scheduler/plan_tool_use.txt +53 -0
  88. tketool/lmc/prompts/templates/agent_scheduler/prepare_tool_call.txt +56 -0
  89. tketool/lmc/prompts/templates/agent_scheduler/re_understand_task.txt +61 -0
  90. tketool/lmc/prompts/templates/agent_scheduler/reason.txt +35 -0
  91. tketool/lmc/prompts/templates/agent_scheduler/replan_task_plan.txt +66 -0
  92. tketool/lmc/prompts/templates/agent_scheduler/summarize_user_need.txt +50 -0
  93. tketool/lmc/prompts/templates/agent_scheduler/understand_task.txt +47 -0
  94. tketool/lmc/prompts/templates/agent_scheduler/validate.txt +41 -0
  95. tketool/lmc/prompts/templates/agent_scheduler/validate_task_plan.txt +46 -0
  96. tketool/lmc/prompts/templates/agents/memory_method_plan.txt +51 -0
  97. tketool/lmc/prompts/templates/agents/memory_range.txt +34 -0
  98. tketool/lmc/prompts/templates/agents/memory_recall.txt +25 -0
  99. tketool/lmc/prompts/templates/agents/memory_thinking_recall.txt +36 -0
  100. tketool/lmc/prompts/templates/agents/rule_compress.txt +26 -0
  101. tketool/lmc/prompts/templates/mcps/context_summary.txt +28 -0
  102. tketool/lmc/prompts/templates/mcps/mcp_page_use.txt +33 -0
  103. tketool/lmc/prompts/templates/mcps/mcp_step_summary.txt +39 -0
  104. tketool/lmc/prompts/templates/mcps/mcp_summary.txt +41 -0
  105. tketool/lmc/prompts/templates/scheduler2/scheduler2_main_decide.txt +55 -0
  106. tketool/lmc/prompts/templates/scheduler2/scheduler2_main_experience_organize.txt +23 -0
  107. tketool/lmc/prompts/templates/scheduler2/scheduler2_main_experience_summarize.txt +33 -0
  108. tketool/lmc/prompts/templates/scheduler2/scheduler2_main_finalize.txt +33 -0
  109. tketool/lmc/prompts/templates/scheduler2/scheduler2_plan_build.txt +42 -0
  110. tketool/lmc/prompts/templates/scheduler2/scheduler2_plan_synthesize.txt +44 -0
  111. tketool/lmc/prompts/templates/scheduler2/scheduler2_task_identify.txt +47 -0
  112. tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_decision.txt +38 -0
  113. tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_experience_write.txt +65 -0
  114. tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_parameter_generate.txt +53 -0
  115. tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_result_verify.txt +48 -0
  116. tketool/lmc/prompts/templates/scheduler2/scheduler2_verify.txt +41 -0
  117. tketool/lmc_console_tool.py +24 -0
  118. tketool_llm-1.3.4.dist-info/METADATA +99 -0
  119. tketool_llm-1.3.4.dist-info/RECORD +122 -0
  120. tketool_llm-1.3.4.dist-info/WHEEL +5 -0
  121. tketool_llm-1.3.4.dist-info/entry_points.txt +2 -0
  122. tketool_llm-1.3.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,7 @@
1
+ """Public large-model API for tketool.
2
+
3
+ The implementation remains available from :mod:`tketool.lmc` for backward
4
+ compatibility. New code should import from :mod:`tketool.llm`.
5
+ """
6
+
7
+ from tketool.lmc import *
@@ -0,0 +1,5 @@
1
+ from tketool.lmc.lmc_linked import *
2
+ from tketool.lmc.lmc_prompt_invoker import *
3
+ from tketool.lmc.prompts.prompt_controller import get_prompt
4
+ from tketool.lmc.llms.openai import OpenAI_Complete_Model, OpenAI_Response_Model
5
+ from tketool.lmc.embeddings import *
@@ -0,0 +1,5 @@
1
+ """LLM agent framework public interfaces."""
2
+
3
+ from tketool.lmc.agent_framework.memory import *
4
+ from tketool.lmc.agent_framework.observer import *
5
+ from tketool.lmc.agent_framework.mcp_tools import *
@@ -0,0 +1,4 @@
1
+ from tketool.lmc.agent_framework.mcp_tools.tool_types import *
2
+ from tketool.lmc.agent_framework.mcp_tools.interfaces import *
3
+ from tketool.lmc.agent_framework.mcp_tools.registry import *
4
+ from tketool.lmc.agent_framework.mcp_tools.function_handler import *
@@ -0,0 +1,35 @@
1
+ from __future__ import annotations
2
+
3
+ from tketool.lmc.agent_framework.mcp_tools import *
4
+
5
+
6
+ @tool_definition(
7
+ name="calculate_revenue",
8
+ description="计算总收入:上午收入 + 下午收入。",
9
+ parameters=[
10
+ ToolParameter(name="morning_count", type="int", description="上午销售数量"),
11
+ ToolParameter(name="morning_price", type="float", description="上午单价"),
12
+ ToolParameter(name="afternoon_count", type="int", description="下午销售数量"),
13
+ ToolParameter(name="afternoon_price", type="float", description="下午单价"),
14
+ ],
15
+ output_schema={"required": ["revenue", "formula"]},
16
+ )
17
+ def calculate_revenue(
18
+ morning_count: int,
19
+ morning_price: float,
20
+ afternoon_count: int,
21
+ afternoon_price: float,
22
+ ) -> dict:
23
+ """计算今日总收入。"""
24
+ revenue = morning_count * morning_price + afternoon_count * afternoon_price
25
+ formula = (
26
+ f"{morning_count} x {morning_price:g} + "
27
+ f"{afternoon_count} x {afternoon_price:g} = {revenue:g}"
28
+ )
29
+ return {"revenue": revenue, "formula": formula}
30
+
31
+
32
+ def build_demo_tool_registry() -> InMemoryToolRegistry:
33
+ tools = InMemoryToolRegistry()
34
+ tools.register(FunctionToolHandler(calculate_revenue))
35
+ return tools
@@ -0,0 +1,224 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+ from inspect import Signature, signature
5
+ from typing import Any
6
+
7
+ from tketool.lmc.agent_framework.mcp_tools.interfaces import ToolHandler
8
+ from tketool.lmc.agent_framework.mcp_tools.tool_types import (
9
+ ToolCall,
10
+ ToolDefinition,
11
+ ToolParameter,
12
+ ToolResult,
13
+ ToolResultStatus,
14
+ )
15
+ from tketool.lmc.agent_framework.observer import FrameworkObserver
16
+
17
+
18
+ class FunctionToolHandler(ToolHandler):
19
+ """把普通 Python 函数适配为 ToolHandler。"""
20
+
21
+ def __init__(self, func: Callable, definition: ToolDefinition | None = None):
22
+ self.func = func
23
+ self.definition = definition or self._definition_from_func(func)
24
+
25
+ def before(self, call: ToolCall) -> ToolCall:
26
+ """执行前补齐默认参数并校验必填参数。"""
27
+ arguments = dict(call.arguments)
28
+ missing = []
29
+ for parameter in self.definition.parameters:
30
+ if parameter.name not in arguments:
31
+ if parameter.required:
32
+ missing.append(parameter.name)
33
+ else:
34
+ arguments[parameter.name] = parameter.default
35
+ if missing:
36
+ raise ValueError(f"缺少必填参数:{', '.join(missing)}")
37
+ call.arguments = arguments
38
+ return call
39
+
40
+ def execute(self, call: ToolCall) -> ToolResult:
41
+ """执行函数并把异常转换为标准 ToolResult。"""
42
+ try:
43
+ content = self.func(**call.arguments)
44
+ except Exception as exc: # noqa: BLE001
45
+ return ToolResult(
46
+ status=ToolResultStatus.FATAL_ERROR,
47
+ error=str(exc),
48
+ retryable=False,
49
+ metadata={"tool_name": self.definition.name},
50
+ )
51
+ return ToolResult(
52
+ status=ToolResultStatus.SUCCESS,
53
+ content=content,
54
+ metadata={"tool_name": self.definition.name},
55
+ )
56
+
57
+ def after(self, call: ToolCall, result: ToolResult) -> ToolResult:
58
+ """执行后补充调用信息。"""
59
+ result.metadata = {
60
+ **result.metadata,
61
+ "call_id": call.call_id,
62
+ "task_id": call.context.task_id,
63
+ "step_id": call.context.step_id,
64
+ }
65
+ return result
66
+
67
+ def validate(self, call: ToolCall, result: ToolResult) -> ToolResult:
68
+ """校验输出是否满足 output_schema 中的 required 字段要求。"""
69
+ if result.status != ToolResultStatus.SUCCESS:
70
+ return result
71
+ required_fields = (self.definition.output_schema or {}).get("required", [])
72
+ if required_fields:
73
+ if not isinstance(result.content, dict):
74
+ return ToolResult(
75
+ status=ToolResultStatus.VALIDATION_ERROR,
76
+ content=result.content,
77
+ error="工具输出不是 dict,无法校验 required 字段。",
78
+ retryable=False,
79
+ metadata=result.metadata,
80
+ )
81
+ missing = [field for field in required_fields if field not in result.content]
82
+ if missing:
83
+ return ToolResult(
84
+ status=ToolResultStatus.VALIDATION_ERROR,
85
+ content=result.content,
86
+ error=f"工具输出缺少字段:{', '.join(missing)}",
87
+ retryable=False,
88
+ metadata=result.metadata,
89
+ )
90
+ return result
91
+
92
+ def run(self, call: ToolCall, observer_object: FrameworkObserver | None = None) -> ToolResult:
93
+ """按 before -> execute -> after -> validate 顺序执行工具。"""
94
+ span_id = None
95
+ if observer_object is not None:
96
+ span_id = observer_object.event_start(
97
+ "mcp.tool_call",
98
+ source="mcp",
99
+ phase="tool",
100
+ task_id=call.context.task_id,
101
+ node_id=call.context.step_id,
102
+ subject={"kind": "tool", "id": self.definition.name},
103
+ payload={
104
+ "tool_name": self.definition.name,
105
+ "call_id": call.call_id,
106
+ "arguments": dict(call.arguments),
107
+ "context_metadata": dict(call.context.metadata),
108
+ },
109
+ )
110
+ try:
111
+ prepared_call = self.before(call)
112
+ except Exception as exc: # noqa: BLE001
113
+ if observer_object is not None:
114
+ observer_object.error(
115
+ "mcp.tool_call_error",
116
+ exc,
117
+ source="mcp",
118
+ phase="tool",
119
+ task_id=call.context.task_id,
120
+ node_id=call.context.step_id,
121
+ payload={"tool_name": self.definition.name, "call_id": call.call_id, "stage": "before"},
122
+ )
123
+ if span_id:
124
+ observer_object.event_end(
125
+ span_id,
126
+ level="error",
127
+ status="failed",
128
+ payload={"tool_name": self.definition.name, "call_id": call.call_id, "stage": "before", "error": str(exc)},
129
+ )
130
+ return ToolResult(
131
+ status=ToolResultStatus.FATAL_ERROR,
132
+ error=str(exc),
133
+ retryable=False,
134
+ metadata={"tool_name": self.definition.name},
135
+ )
136
+ attempts = max(1, self.definition.retry_policy.max_attempts)
137
+ last_result: ToolResult | None = None
138
+ for attempt in range(1, attempts + 1):
139
+ result = self.execute(prepared_call)
140
+ result.metadata = {**result.metadata, "attempt": attempt}
141
+ result = self.after(prepared_call, result)
142
+ result = self.validate(prepared_call, result)
143
+ last_result = result
144
+ if observer_object is not None:
145
+ observer_object.record(
146
+ "mcp.tool_call_attempt",
147
+ source="mcp",
148
+ phase="tool",
149
+ level="error" if result.status != ToolResultStatus.SUCCESS else "info",
150
+ task_id=prepared_call.context.task_id,
151
+ node_id=prepared_call.context.step_id,
152
+ message=result.error or "",
153
+ payload={
154
+ "tool_name": self.definition.name,
155
+ "call_id": prepared_call.call_id,
156
+ "attempt": attempt,
157
+ "status": result.status,
158
+ "retryable": result.retryable,
159
+ },
160
+ )
161
+ # 只有 retry_policy 明确允许的状态才进入下一次尝试。
162
+ if result.status not in self.definition.retry_policy.retry_on:
163
+ if observer_object is not None:
164
+ observer_object.event_end(
165
+ span_id,
166
+ level="error" if result.status != ToolResultStatus.SUCCESS else "info",
167
+ status=result.status,
168
+ message=result.error or "",
169
+ payload={
170
+ "tool_name": self.definition.name,
171
+ "call_id": prepared_call.call_id,
172
+ "status": result.status,
173
+ "attempts": attempt,
174
+ "has_content": result.content is not None,
175
+ },
176
+ )
177
+ return result
178
+ assert last_result is not None
179
+ if observer_object is not None:
180
+ observer_object.event_end(
181
+ span_id,
182
+ level="error" if last_result.status != ToolResultStatus.SUCCESS else "info",
183
+ status=last_result.status,
184
+ message=last_result.error or "",
185
+ payload={
186
+ "tool_name": self.definition.name,
187
+ "call_id": prepared_call.call_id,
188
+ "status": last_result.status,
189
+ "attempts": attempts,
190
+ "has_content": last_result.content is not None,
191
+ },
192
+ )
193
+ return last_result
194
+
195
+ def _definition_from_func(self, func: Callable) -> ToolDefinition:
196
+ """从函数签名生成工具定义,优先使用装饰器附加的定义。"""
197
+ if hasattr(func, "_tool_definition"):
198
+ return func._tool_definition
199
+ parameters = [
200
+ ToolParameter(
201
+ name=name,
202
+ type=self._type_name(param.annotation),
203
+ description=f"函数参数 {name}",
204
+ required=param.default is param.empty,
205
+ default=None if param.default is param.empty else param.default,
206
+ )
207
+ for name, param in signature(func).parameters.items()
208
+ ]
209
+ return ToolDefinition(
210
+ name=func.__name__,
211
+ description=func.__doc__ or f"函数工具:{func.__name__}",
212
+ parameters=parameters,
213
+ )
214
+
215
+ def _type_name(self, annotation: Any) -> str:
216
+ """把 Python 类型注解转为简短字符串。"""
217
+ if annotation is Signature.empty:
218
+ return "Any"
219
+ return getattr(annotation, "__name__", str(annotation))
220
+
221
+
222
+ def build_function_tool_handler(func: Callable) -> FunctionToolHandler:
223
+ """从普通函数构造 FunctionToolHandler。"""
224
+ return FunctionToolHandler(func)
@@ -0,0 +1,91 @@
1
+ from abc import ABC, abstractmethod
2
+ from collections.abc import Callable
3
+
4
+ from tketool.lmc.agent_framework.observer import FrameworkObserver
5
+ from tketool.lmc.agent_framework.mcp_tools.tool_types import (
6
+ ToolCall,
7
+ ToolDefinition,
8
+ ToolResult,
9
+ )
10
+
11
+
12
+ class ToolHandler(ABC):
13
+ """工具处理器接口,定义一次工具调用的完整生命周期。"""
14
+
15
+ definition: ToolDefinition
16
+
17
+ @abstractmethod
18
+ def before(self, call: ToolCall) -> ToolCall:
19
+ """执行前处理,例如参数补全、权限检查或日志记录。"""
20
+ ...
21
+
22
+ @abstractmethod
23
+ def execute(self, call: ToolCall) -> ToolResult:
24
+ """执行实际工具逻辑。"""
25
+ ...
26
+
27
+ @abstractmethod
28
+ def after(self, call: ToolCall, result: ToolResult) -> ToolResult:
29
+ """执行后处理,例如格式整理、指标记录或结果裁剪。"""
30
+ ...
31
+
32
+ @abstractmethod
33
+ def validate(self, call: ToolCall, result: ToolResult) -> ToolResult:
34
+ """校验工具结果是否满足调度步骤要求。"""
35
+ ...
36
+
37
+ def run(self, call: ToolCall, observer_object: FrameworkObserver | None = None) -> ToolResult:
38
+ """执行完整工具生命周期。"""
39
+ prepared_call = self.before(call)
40
+ result = self.execute(prepared_call)
41
+ result = self.after(prepared_call, result)
42
+ return self.validate(prepared_call, result)
43
+
44
+
45
+ class ToolRegistry(ABC):
46
+ """工具注册表接口,供调度器按名称查找可用工具。"""
47
+
48
+ @property
49
+ @abstractmethod
50
+ def mcplibcode(self) -> str:
51
+ """当前注册工具名集合的稳定短 ID。"""
52
+ ...
53
+
54
+ @abstractmethod
55
+ def register(self, handler: ToolHandler) -> None:
56
+ """注册一个工具处理器。"""
57
+ ...
58
+
59
+ @abstractmethod
60
+ def get(self, name: str) -> ToolHandler:
61
+ """根据工具名称获取处理器。"""
62
+ ...
63
+
64
+ @abstractmethod
65
+ def list_definitions(self) -> list[ToolDefinition]:
66
+ """列出当前可用工具定义。"""
67
+ ...
68
+
69
+ def search_definitions(self, query: str, top_k: int = 8) -> list[ToolDefinition]:
70
+ """按查询文本检索候选工具定义;默认实现回退到全量列表截断。"""
71
+ return self.list_definitions()[:top_k]
72
+
73
+
74
+ def tool_definition(
75
+ name: str,
76
+ description: str,
77
+ parameters: list | None = None,
78
+ **kwargs,
79
+ ) -> Callable:
80
+ """为普通函数附加工具定义元数据。"""
81
+
82
+ def decorator(func: Callable) -> Callable:
83
+ func._tool_definition = ToolDefinition(
84
+ name=name,
85
+ description=description,
86
+ parameters=parameters or [],
87
+ **kwargs,
88
+ )
89
+ return func
90
+
91
+ return decorator
@@ -0,0 +1,76 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import re
5
+
6
+ from tketool.lmc.agent_framework.mcp_tools.interfaces import ToolHandler, ToolRegistry
7
+ from tketool.lmc.agent_framework.mcp_tools.tool_types import ToolDefinition
8
+
9
+
10
+ class ToolRegistrationError(ValueError):
11
+ """工具注册错误。"""
12
+
13
+
14
+ class ToolNotFoundError(KeyError):
15
+ """工具不存在错误。"""
16
+
17
+
18
+ class InMemoryToolRegistry(ToolRegistry):
19
+ """内存版工具注册表,用于本地运行和单元测试。"""
20
+
21
+ def __init__(self):
22
+ self._handlers: dict[str, ToolHandler] = {}
23
+
24
+ @property
25
+ def mcplibcode(self) -> str:
26
+ """当前工具名集合的稳定短 ID。"""
27
+ tool_names = sorted(self._handlers)
28
+ raw = "\n".join(tool_names)
29
+ return hashlib.sha1(raw.encode("utf-8")).hexdigest()[:12]
30
+
31
+ def register(self, handler: ToolHandler) -> None:
32
+ """注册一个工具处理器;重名工具默认拒绝。"""
33
+ name = handler.definition.name
34
+ if name in self._handlers:
35
+ raise ToolRegistrationError(f"工具已注册:{name}")
36
+ self._handlers[name] = handler
37
+
38
+ def get(self, name: str) -> ToolHandler:
39
+ """根据名称获取工具处理器;不存在时抛出明确异常。"""
40
+ if name not in self._handlers:
41
+ raise ToolNotFoundError(f"工具不存在:{name}")
42
+ return self._handlers[name]
43
+
44
+ def list_definitions(self) -> list[ToolDefinition]:
45
+ """按工具名稳定列出工具定义。"""
46
+ return [
47
+ self._handlers[name].definition
48
+ for name in sorted(self._handlers)
49
+ ]
50
+
51
+ def search_definitions(self, query: str, top_k: int = 8) -> list[ToolDefinition]:
52
+ """用轻量关键词打分检索工具定义。"""
53
+ definitions = self.list_definitions()
54
+ query_terms = _tokenize_tool_text(query)
55
+ if not query_terms:
56
+ return definitions[:top_k]
57
+ scored = []
58
+ for definition in definitions:
59
+ text = " ".join(
60
+ [
61
+ definition.name,
62
+ definition.description,
63
+ " ".join(parameter.name for parameter in definition.parameters),
64
+ " ".join(parameter.description for parameter in definition.parameters),
65
+ " ".join(str(value) for value in definition.metadata.values()),
66
+ ]
67
+ )
68
+ terms = set(_tokenize_tool_text(text))
69
+ score = sum(1 for term in query_terms if term in terms)
70
+ scored.append((score, definition.name, definition))
71
+ scored.sort(key=lambda item: (-item[0], item[1]))
72
+ return [definition for score, _, definition in scored[:top_k] if score > 0] or definitions[:top_k]
73
+
74
+
75
+ def _tokenize_tool_text(text: str) -> list[str]:
76
+ return [token.lower() for token in re.findall(r"[A-Za-z0-9_/-]+|[\u4e00-\u9fff]{2,}", text)]
@@ -0,0 +1,73 @@
1
+ """MCP Tools 模块最小运行示例。
2
+
3
+ 运行方式:
4
+ python -m tketool.lmc.agent_framework.mcp_tools.simple_code
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import sys
10
+ from pathlib import Path
11
+
12
+
13
+ # 允许从当前文件直接运行,同时避免 mcp_tools 目录里的模块名影响标准库导入。
14
+ for path in list(sys.path):
15
+ if path == "" or path.endswith("/lmc/agent_framework/mcp_tools"):
16
+ sys.path.remove(path)
17
+
18
+ PROJECT_ROOT = Path(__file__).resolve().parents[4]
19
+ if str(PROJECT_ROOT) not in sys.path:
20
+ sys.path.insert(0, str(PROJECT_ROOT))
21
+
22
+ from tketool.lmc.agent_framework.mcp_tools import (
23
+ FunctionToolHandler,
24
+ InMemoryToolRegistry,
25
+ ToolCall,
26
+ ToolContext,
27
+ ToolParameter,
28
+ ToolResultStatus,
29
+ tool_definition,
30
+ )
31
+
32
+
33
+ @tool_definition(
34
+ name="calculate_revenue",
35
+ description="计算收入:数量乘以单价。",
36
+ parameters=[
37
+ ToolParameter(name="count", type="int", description="销售数量"),
38
+ ToolParameter(name="price", type="float", description="单价"),
39
+ ],
40
+ output_schema={"required": ["revenue"]},
41
+ )
42
+ def calculate_revenue(count: int, price: float) -> dict:
43
+ """计算销售收入。"""
44
+ return {"revenue": count * price}
45
+
46
+
47
+ def main() -> None:
48
+ registry = InMemoryToolRegistry()
49
+ registry.register(FunctionToolHandler(calculate_revenue))
50
+
51
+ print("已注册工具:")
52
+ for definition in registry.list_definitions():
53
+ print(f"- {definition.name}: {definition.description}")
54
+
55
+ call = ToolCall(
56
+ tool_name="calculate_revenue",
57
+ arguments={"count": 3, "price": 20},
58
+ context=ToolContext(task_id="demo-task", step_id="execute_tool"),
59
+ call_id="tool-call-1",
60
+ )
61
+ handler = registry.get(call.tool_name)
62
+ result = handler.run(call)
63
+
64
+ print("\n工具调用:")
65
+ print(f"输入: {call.arguments}")
66
+ print(f"状态: {result.status.value}")
67
+ print(f"输出: {result.content}")
68
+ if result.status != ToolResultStatus.SUCCESS:
69
+ print(f"错误: {result.error}")
70
+
71
+
72
+ if __name__ == "__main__":
73
+ main()
@@ -0,0 +1,122 @@
1
+ from dataclasses import dataclass, field
2
+ from datetime import datetime
3
+ from enum import Enum
4
+ from typing import Any, Optional
5
+
6
+
7
+ class ToolRisk(str, Enum):
8
+ """工具风险等级,用于调度器决定是否需要额外确认或降级。"""
9
+
10
+ # 低风险工具,例如只读查询、纯计算、格式转换。
11
+ LOW = "low"
12
+ # 中风险工具,例如写入临时文件、调用外部服务、产生费用。
13
+ MEDIUM = "medium"
14
+ # 高风险工具,例如删除数据、提交变更、影响生产系统。
15
+ HIGH = "high"
16
+
17
+
18
+ class ToolResultStatus(str, Enum):
19
+ """工具调用结果状态。"""
20
+
21
+ # 调用成功。
22
+ SUCCESS = "success"
23
+ # 可重试错误,例如短暂网络失败、限流。
24
+ RETRYABLE_ERROR = "retryable_error"
25
+ # 不可重试错误,例如参数非法、工具不存在、权限不足。
26
+ FATAL_ERROR = "fatal_error"
27
+ # 工具执行完成,但结果不满足输出要求。
28
+ VALIDATION_ERROR = "validation_error"
29
+
30
+
31
+ @dataclass
32
+ class RetryPolicy:
33
+ """工具重试策略。"""
34
+
35
+ # 最大尝试次数,包含第一次调用。
36
+ max_attempts: int = 1
37
+ # 哪些结果状态允许重试。
38
+ retry_on: list[ToolResultStatus] = field(
39
+ default_factory=lambda: [ToolResultStatus.RETRYABLE_ERROR]
40
+ )
41
+
42
+
43
+ @dataclass
44
+ class ToolParameter:
45
+ """工具参数定义。"""
46
+
47
+ # 参数名,与 ToolCall.arguments 中的 key 对应。
48
+ name: str
49
+ # 参数类型描述,例如 str、int、float、bool、dict。
50
+ type: str
51
+ # 参数说明,供 LLM 或调用方理解如何填写。
52
+ description: str
53
+ # 是否必填;缺失必填参数时 before 阶段会拒绝。
54
+ required: bool = True
55
+ # 默认值;非必填参数缺失时可自动补齐。
56
+ default: Any = None
57
+
58
+
59
+ @dataclass
60
+ class ToolDefinition:
61
+ """工具能力定义,描述名称、参数、输出和风险等级。"""
62
+
63
+ # 工具唯一名称,注册表按该字段查找 ToolHandler。
64
+ name: str
65
+ # 工具用途说明,供调度器或 LLM 选择工具时使用。
66
+ description: str
67
+ # 工具参数列表。
68
+ parameters: list[ToolParameter] = field(default_factory=list)
69
+ # 输出结构约束;第一版只做轻量存在性校验。
70
+ output_schema: Optional[dict[str, Any]] = None
71
+ # 工具风险等级。
72
+ risk: ToolRisk = ToolRisk.LOW
73
+ # 工具重试策略。
74
+ retry_policy: RetryPolicy = field(default_factory=RetryPolicy)
75
+ # 工具扩展信息,例如标签、版本、外部系统名称。
76
+ metadata: dict[str, Any] = field(default_factory=dict)
77
+
78
+
79
+ @dataclass
80
+ class ToolContext:
81
+ """工具调用上下文,记录任务、步骤和调用侧元数据。"""
82
+
83
+ # 调用所属任务 ID。
84
+ task_id: str
85
+ # 调用所属调度步骤 ID。
86
+ step_id: str
87
+ # 调用用户或主体 ID。
88
+ user: Optional[str] = None
89
+ # 调用侧扩展信息,例如 trace_id、审批信息、环境。
90
+ metadata: dict[str, Any] = field(default_factory=dict)
91
+
92
+
93
+ @dataclass
94
+ class ToolCall:
95
+ """一次工具调用请求。"""
96
+
97
+ # 要调用的工具名称。
98
+ tool_name: str
99
+ # 工具入参。
100
+ arguments: dict[str, Any]
101
+ # 工具调用上下文。
102
+ context: ToolContext
103
+ # 调用 ID,用于日志、重试和幂等;为空时可由调用方后续补齐。
104
+ call_id: Optional[str] = None
105
+ # 调用创建时间。
106
+ created_at: datetime = field(default_factory=datetime.now)
107
+
108
+
109
+ @dataclass
110
+ class ToolResult:
111
+ """一次工具调用结果。"""
112
+
113
+ # 调用结果状态。
114
+ status: ToolResultStatus
115
+ # 成功时的返回内容。
116
+ content: Any = None
117
+ # 失败时的错误说明。
118
+ error: Optional[str] = None
119
+ # 是否可重试,通常和 status/retry_policy 联合使用。
120
+ retryable: bool = False
121
+ # 结果扩展信息,例如耗时、尝试次数、校验细节。
122
+ metadata: dict[str, Any] = field(default_factory=dict)
@@ -0,0 +1,2 @@
1
+ from tketool.lmc.agent_framework.memory.types import *
2
+ from tketool.lmc.agent_framework.memory.interfaces import *