tketool.llm 1.3.4__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 (127) hide show
  1. tketool_llm-1.3.4/PKG-INFO +99 -0
  2. tketool_llm-1.3.4/README.md +71 -0
  3. tketool_llm-1.3.4/pyproject.toml +46 -0
  4. tketool_llm-1.3.4/setup.cfg +4 -0
  5. tketool_llm-1.3.4/src/tketool/llm/__init__.py +7 -0
  6. tketool_llm-1.3.4/src/tketool/lmc/__init__.py +5 -0
  7. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/__init__.py +5 -0
  8. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/__init__.py +4 -0
  9. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/demo_tools.py +35 -0
  10. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/function_handler.py +224 -0
  11. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/interfaces.py +91 -0
  12. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/registry.py +76 -0
  13. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/simple_code.py +73 -0
  14. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/tool_types.py +122 -0
  15. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/__init__.py +2 -0
  16. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/interfaces.py +71 -0
  17. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/local_memory.py +160 -0
  18. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/memory_imps/__init__.py +49 -0
  19. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/memory_imps/hindsight_like.py +532 -0
  20. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/memory_imps/ml2_indexes.py +25 -0
  21. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/__init__.py +43 -0
  22. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/in_memory_bank_storage.py +25 -0
  23. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/in_memory_entity_index.py +61 -0
  24. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/in_memory_sparse_index.py +32 -0
  25. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/in_memory_temporal_index.py +28 -0
  26. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/in_memory_vector_index.py +34 -0
  27. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/ml2_bank_storage.py +90 -0
  28. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/ml2_entity_index.py +73 -0
  29. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/ml2_sparse_index.py +41 -0
  30. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/ml2_temporal_index.py +35 -0
  31. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/ml2_vector_index.py +44 -0
  32. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/types.py +239 -0
  33. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/__init__.py +13 -0
  34. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/observer.py +322 -0
  35. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/redactor.py +68 -0
  36. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/report.py +67 -0
  37. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/sink.py +57 -0
  38. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/types.py +74 -0
  39. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/__init__.py +4 -0
  40. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/base.py +32 -0
  41. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/chains/__init__.py +4 -0
  42. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/chains/base.py +492 -0
  43. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/chains/main.py +674 -0
  44. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/chains/plan_main.py +368 -0
  45. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/chains/tool_call.py +461 -0
  46. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/graph.py +19 -0
  47. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/memory_kit/__init__.py +35 -0
  48. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/memory_kit/common.py +47 -0
  49. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/memory_kit/main_chain_memory.py +82 -0
  50. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/memory_kit/tool_call_memory.py +214 -0
  51. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/node_types.py +12 -0
  52. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/__init__.py +21 -0
  53. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/common.py +5 -0
  54. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/decision.py +25 -0
  55. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/info_summary.py +15 -0
  56. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/main_chain/__init__.py +3 -0
  57. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/main_chain/experience.py +87 -0
  58. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/main_chain/finalize.py +83 -0
  59. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/__init__.py +9 -0
  60. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_build.py +125 -0
  61. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_check.py +60 -0
  62. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_select.py +56 -0
  63. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_synthesize.py +101 -0
  64. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_types.py +60 -0
  65. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_update.py +71 -0
  66. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/subtask_run.py +77 -0
  67. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/task_identify.py +133 -0
  68. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/__init__.py +5 -0
  69. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/parameter_generate.py +134 -0
  70. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_call.py +109 -0
  71. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_decision.py +128 -0
  72. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_experience_write.py +81 -0
  73. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_result_verify.py +99 -0
  74. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/verify.py +135 -0
  75. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/prompting.py +126 -0
  76. tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/types.py +194 -0
  77. tketool_llm-1.3.4/src/tketool/lmc/embeddings.py +17 -0
  78. tketool_llm-1.3.4/src/tketool/lmc/llms/__init__.py +1 -0
  79. tketool_llm-1.3.4/src/tketool/lmc/llms/embeddings.py +215 -0
  80. tketool_llm-1.3.4/src/tketool/lmc/llms/openai.py +326 -0
  81. tketool_llm-1.3.4/src/tketool/lmc/lmc_linked.py +604 -0
  82. tketool_llm-1.3.4/src/tketool/lmc/lmc_linked_flow.py +7 -0
  83. tketool_llm-1.3.4/src/tketool/lmc/lmc_prompt_invoker.py +426 -0
  84. tketool_llm-1.3.4/src/tketool/lmc/models.py +97 -0
  85. tketool_llm-1.3.4/src/tketool/lmc/prompts/__init__.py +0 -0
  86. tketool_llm-1.3.4/src/tketool/lmc/prompts/prompt_controller.py +462 -0
  87. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/auto_repair.txt +38 -0
  88. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/context_compact.txt +41 -0
  89. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/context_resolve_reference.txt +42 -0
  90. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/decompose_task_plan.txt +71 -0
  91. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/plan_tool_use.txt +53 -0
  92. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/prepare_tool_call.txt +56 -0
  93. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/re_understand_task.txt +61 -0
  94. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/reason.txt +35 -0
  95. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/replan_task_plan.txt +66 -0
  96. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/summarize_user_need.txt +50 -0
  97. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/understand_task.txt +47 -0
  98. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/validate.txt +41 -0
  99. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/validate_task_plan.txt +46 -0
  100. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agents/memory_method_plan.txt +51 -0
  101. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agents/memory_range.txt +34 -0
  102. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agents/memory_recall.txt +25 -0
  103. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agents/memory_thinking_recall.txt +36 -0
  104. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agents/rule_compress.txt +26 -0
  105. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/mcps/context_summary.txt +28 -0
  106. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/mcps/mcp_page_use.txt +33 -0
  107. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/mcps/mcp_step_summary.txt +39 -0
  108. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/mcps/mcp_summary.txt +41 -0
  109. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_main_decide.txt +55 -0
  110. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_main_experience_organize.txt +23 -0
  111. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_main_experience_summarize.txt +33 -0
  112. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_main_finalize.txt +33 -0
  113. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_plan_build.txt +42 -0
  114. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_plan_synthesize.txt +44 -0
  115. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_task_identify.txt +47 -0
  116. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_decision.txt +38 -0
  117. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_experience_write.txt +65 -0
  118. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_parameter_generate.txt +53 -0
  119. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_result_verify.txt +48 -0
  120. tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_verify.txt +41 -0
  121. tketool_llm-1.3.4/src/tketool/lmc_console_tool.py +24 -0
  122. tketool_llm-1.3.4/src/tketool.llm.egg-info/PKG-INFO +99 -0
  123. tketool_llm-1.3.4/src/tketool.llm.egg-info/SOURCES.txt +125 -0
  124. tketool_llm-1.3.4/src/tketool.llm.egg-info/dependency_links.txt +1 -0
  125. tketool_llm-1.3.4/src/tketool.llm.egg-info/entry_points.txt +2 -0
  126. tketool_llm-1.3.4/src/tketool.llm.egg-info/requires.txt +16 -0
  127. tketool_llm-1.3.4/src/tketool.llm.egg-info/top_level.txt +1 -0
@@ -0,0 +1,99 @@
1
+ Metadata-Version: 2.4
2
+ Name: tketool.llm
3
+ Version: 1.3.4
4
+ Summary: OpenAI-compatible LLM, structured prompt, scheduler, and memory APIs for tketool
5
+ Author-email: Ke <jiangke1207@icloud.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://pypi.org/project/tketool.llm/
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: tketool.core==1.3.4
16
+ Requires-Dist: tketool.ml==1.3.4
17
+ Requires-Dist: openai<4,>=3
18
+ Requires-Dist: httpx<1,>=0.27
19
+ Requires-Dist: langchain-core<1.7,>=1.6
20
+ Requires-Dist: pydantic<3,>=2.10
21
+ Provides-Extra: local-embeddings
22
+ Requires-Dist: torch<3,>=2.4; extra == "local-embeddings"
23
+ Requires-Dist: transformers<6,>=5; extra == "local-embeddings"
24
+ Provides-Extra: memory
25
+ Requires-Dist: hindsight-all<1,>=0.9; extra == "memory"
26
+ Provides-Extra: test
27
+ Requires-Dist: pytest<9,>=8; extra == "test"
28
+
29
+ # tketool.llm
30
+
31
+ OpenAI-compatible large-model access, structured-output prompts, embeddings,
32
+ memory, tools, and the current scheduler.
33
+
34
+ ```bash
35
+ pip install tketool.llm
36
+ ```
37
+
38
+ ## Chat Completions
39
+
40
+ ```python
41
+ import os
42
+
43
+ from tketool.llm import OpenAI_Complete_Model
44
+
45
+ llm = OpenAI_Complete_Model(
46
+ model_name="gpt-4o-mini",
47
+ apitoken=os.environ["OPENAI_API_KEY"],
48
+ base_url="https://api.openai.com/v1",
49
+ call_dict={"temperature": 0.2},
50
+ )
51
+
52
+ text = llm("用三句话解释向量检索", return_detail=False)
53
+ print(text)
54
+ ```
55
+
56
+ ## Responses API
57
+
58
+ ```python
59
+ import os
60
+
61
+ from tketool.llm import OpenAI_Response_Model
62
+
63
+ llm = OpenAI_Response_Model(
64
+ model_name="gpt-5-mini",
65
+ apitoken=os.environ["OPENAI_API_KEY"],
66
+ base_url="https://api.openai.com/v1",
67
+ call_dict={"max_output_tokens": 300},
68
+ )
69
+
70
+ text, detail = llm("给出一个最小 RAG 流程", return_detail=True)
71
+ print(text)
72
+ print(detail)
73
+ ```
74
+
75
+ Both transports accept a complete `messages` list and return the same detail
76
+ shape. OpenAI-compatible gateways are supported by changing `base_url` and
77
+ `model_name`.
78
+
79
+ ```python
80
+ messages = [
81
+ {"role": "system", "content": "回答要简洁。"},
82
+ {"role": "user", "content": "什么是结构化输出?"},
83
+ ]
84
+
85
+ answer = llm("", return_detail=False, messages=messages)
86
+ ```
87
+
88
+ New code should import from `tketool.llm`. The existing `tketool.lmc` path is
89
+ kept as a compatibility API during migration.
90
+
91
+ Local Hugging Face embeddings are optional:
92
+
93
+ ```bash
94
+ pip install "tketool.llm[local-embeddings]"
95
+ ```
96
+
97
+ The optional `memory` extra requires Python 3.11 or newer because its external
98
+ backend does. The legacy `agent`/`context` implementation was removed because
99
+ it depended on the retired scheduler; use `scheduler2` for current agent flows.
@@ -0,0 +1,71 @@
1
+ # tketool.llm
2
+
3
+ OpenAI-compatible large-model access, structured-output prompts, embeddings,
4
+ memory, tools, and the current scheduler.
5
+
6
+ ```bash
7
+ pip install tketool.llm
8
+ ```
9
+
10
+ ## Chat Completions
11
+
12
+ ```python
13
+ import os
14
+
15
+ from tketool.llm import OpenAI_Complete_Model
16
+
17
+ llm = OpenAI_Complete_Model(
18
+ model_name="gpt-4o-mini",
19
+ apitoken=os.environ["OPENAI_API_KEY"],
20
+ base_url="https://api.openai.com/v1",
21
+ call_dict={"temperature": 0.2},
22
+ )
23
+
24
+ text = llm("用三句话解释向量检索", return_detail=False)
25
+ print(text)
26
+ ```
27
+
28
+ ## Responses API
29
+
30
+ ```python
31
+ import os
32
+
33
+ from tketool.llm import OpenAI_Response_Model
34
+
35
+ llm = OpenAI_Response_Model(
36
+ model_name="gpt-5-mini",
37
+ apitoken=os.environ["OPENAI_API_KEY"],
38
+ base_url="https://api.openai.com/v1",
39
+ call_dict={"max_output_tokens": 300},
40
+ )
41
+
42
+ text, detail = llm("给出一个最小 RAG 流程", return_detail=True)
43
+ print(text)
44
+ print(detail)
45
+ ```
46
+
47
+ Both transports accept a complete `messages` list and return the same detail
48
+ shape. OpenAI-compatible gateways are supported by changing `base_url` and
49
+ `model_name`.
50
+
51
+ ```python
52
+ messages = [
53
+ {"role": "system", "content": "回答要简洁。"},
54
+ {"role": "user", "content": "什么是结构化输出?"},
55
+ ]
56
+
57
+ answer = llm("", return_detail=False, messages=messages)
58
+ ```
59
+
60
+ New code should import from `tketool.llm`. The existing `tketool.lmc` path is
61
+ kept as a compatibility API during migration.
62
+
63
+ Local Hugging Face embeddings are optional:
64
+
65
+ ```bash
66
+ pip install "tketool.llm[local-embeddings]"
67
+ ```
68
+
69
+ The optional `memory` extra requires Python 3.11 or newer because its external
70
+ backend does. The legacy `agent`/`context` implementation was removed because
71
+ it depended on the retired scheduler; use `scheduler2` for current agent flows.
@@ -0,0 +1,46 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "tketool.llm"
7
+ version = "1.3.4"
8
+ description = "OpenAI-compatible LLM, structured prompt, scheduler, and memory APIs for tketool"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [{ name = "Ke", email = "jiangke1207@icloud.com" }]
13
+ dependencies = [
14
+ "tketool.core==1.3.4",
15
+ "tketool.ml==1.3.4",
16
+ "openai>=3,<4",
17
+ "httpx>=0.27,<1",
18
+ "langchain-core>=1.6,<1.7",
19
+ "pydantic>=2.10,<3",
20
+ ]
21
+ classifiers = [
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Operating System :: OS Independent",
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+ local-embeddings = ["torch>=2.4,<3", "transformers>=5,<6"]
31
+ memory = ["hindsight-all>=0.9,<1"]
32
+ test = ["pytest>=8,<9"]
33
+
34
+ [project.scripts]
35
+ lmc = "tketool.lmc_console_tool:main"
36
+
37
+ [project.urls]
38
+ Homepage = "https://pypi.org/project/tketool.llm/"
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+ include = ["tketool*"]
43
+ namespaces = true
44
+
45
+ [tool.setuptools.package-data]
46
+ "tketool.lmc.prompts" = ["templates/*/*.txt"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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)]