python-library-ai-agent 0.1.0__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 (62) hide show
  1. ai_agent/__init__.py +66 -0
  2. ai_agent/agent.py +122 -0
  3. ai_agent/app/__init__.py +10 -0
  4. ai_agent/app/_workspace.py +127 -0
  5. ai_agent/app/app.py +321 -0
  6. ai_agent/app/harness_io.py +109 -0
  7. ai_agent/app/output_format.py +77 -0
  8. ai_agent/app/packet.py +39 -0
  9. ai_agent/app/session.py +742 -0
  10. ai_agent/app/session_store.py +85 -0
  11. ai_agent/builtin_tools/__init__.py +18 -0
  12. ai_agent/builtin_tools/current_time.py +39 -0
  13. ai_agent/builtin_tools/pack.py +20 -0
  14. ai_agent/builtin_tools/prefix.py +11 -0
  15. ai_agent/context.py +151 -0
  16. ai_agent/harness/__init__.py +3 -0
  17. ai_agent/harness/current_time.py +25 -0
  18. ai_agent/harness/harness.py +324 -0
  19. ai_agent/harness/process.py +115 -0
  20. ai_agent/harness/prompts.py +38 -0
  21. ai_agent/harness/sandbox.py +139 -0
  22. ai_agent/json_extract.py +70 -0
  23. ai_agent/listener.py +172 -0
  24. ai_agent/llm.py +39 -0
  25. ai_agent/llm_openai.py +117 -0
  26. ai_agent/loop.py +124 -0
  27. ai_agent/mcp_config.py +54 -0
  28. ai_agent/mcp_loader.py +110 -0
  29. ai_agent/memory/__init__.py +9 -0
  30. ai_agent/memory/compression_work.py +71 -0
  31. ai_agent/memory/compressor.py +339 -0
  32. ai_agent/memory/config.py +40 -0
  33. ai_agent/memory/context_builder.py +57 -0
  34. ai_agent/memory/memory_system.py +561 -0
  35. ai_agent/memory/models.py +76 -0
  36. ai_agent/memory/snapshot_merge.py +158 -0
  37. ai_agent/memory/store.py +107 -0
  38. ai_agent/memory/worker.py +227 -0
  39. ai_agent/plan/__init__.py +15 -0
  40. ai_agent/plan/complete.py +64 -0
  41. ai_agent/plan/delivery.py +41 -0
  42. ai_agent/plan/display.py +46 -0
  43. ai_agent/plan/models.py +44 -0
  44. ai_agent/plan/parse.py +39 -0
  45. ai_agent/plan/planner.py +204 -0
  46. ai_agent/plan/runner.py +281 -0
  47. ai_agent/react_tool_turn.py +39 -0
  48. ai_agent/rule/__init__.py +3 -0
  49. ai_agent/rule/rules.py +36 -0
  50. ai_agent/skill/__init__.py +5 -0
  51. ai_agent/skill/builtin_registry.py +56 -0
  52. ai_agent/skill/catalog.py +104 -0
  53. ai_agent/skill/frontmatter.py +83 -0
  54. ai_agent/skill/manager.py +486 -0
  55. ai_agent/skill/models.py +31 -0
  56. ai_agent/skill/roots.py +150 -0
  57. ai_agent/skill/skill_kit.py +80 -0
  58. ai_agent/skill/tool_declarations.py +68 -0
  59. ai_agent/tools.py +123 -0
  60. python_library_ai_agent-0.1.0.dist-info/METADATA +10 -0
  61. python_library_ai_agent-0.1.0.dist-info/RECORD +62 -0
  62. python_library_ai_agent-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping, Sequence
4
+ from pathlib import Path
5
+
6
+ from ai_agent.skill.manager import SkillManager
7
+ from ai_agent.tools import Tool
8
+
9
+
10
+ class SkillKit:
11
+ """
12
+ 技能区入口:扫描、启用与工具导出委托底层管理器。
13
+
14
+ 技能仓库运行时只读;导出列表含管理工具与当前已启用子工具。
15
+
16
+ Args:
17
+ roots: 技能根目录;可为单路径、路径序列或根键到路径的映射
18
+ manager: 已构造的管理器;未传则按 roots 新建
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ roots: Mapping[str, Path | str] | Sequence[Path | str] | Path | str,
24
+ *,
25
+ manager: SkillManager | None = None,
26
+ ) -> None:
27
+ if manager is None:
28
+ self._manager = SkillManager(roots)
29
+ else:
30
+ self._manager = manager
31
+
32
+ @property
33
+ def manager(self) -> SkillManager:
34
+ """底层动态能力管理器。"""
35
+ return self._manager
36
+
37
+ @property
38
+ def root_keys(self) -> tuple[str, ...]:
39
+ """已配置的根键名。"""
40
+ return self._manager.root_keys
41
+
42
+ def list_skills(self, root_key: str = "") -> str:
43
+ """扫描 skill 根目录并列出摘要。"""
44
+ return self._manager.list_skills(root_key)
45
+
46
+ def get_metadata(self, skill_ref: str) -> str:
47
+ """读取 frontmatter 元数据。"""
48
+ return self._manager.get_metadata(skill_ref)
49
+
50
+ def enable_skill(self, skill_ref: str) -> str:
51
+ """启用 skill 及其子工具。"""
52
+ return self._manager.enable_skill(skill_ref)
53
+
54
+ def disable_skill(self, skill_ref: str) -> str:
55
+ """停用 skill。"""
56
+ return self._manager.disable_skill(skill_ref)
57
+
58
+ def refresh(self) -> str:
59
+ """重新扫描 skill 根。"""
60
+ return self._manager.refresh()
61
+
62
+ def roots_info(self) -> str:
63
+ """说明 skill 根目录约束。"""
64
+ return self._manager.roots_info()
65
+
66
+ def build_management_tools(self) -> list[Tool]:
67
+ """仅 skill 管理工具。"""
68
+ return self._manager.build_management_tools()
69
+
70
+ def build_enabled_tools(self) -> list[Tool]:
71
+ """仅已启用 skill 的子工具。"""
72
+ return self._manager.build_enabled_tools()
73
+
74
+ def build_all_flat_tools(self) -> list[Tool]:
75
+ """管理工具与已启用子工具。"""
76
+ return self._manager.build_all_flat_tools()
77
+
78
+ def build_tools(self) -> list[Tool]:
79
+ """管理工具与已启用子工具(兼容旧用法)。"""
80
+ return self.build_all_flat_tools()
@@ -0,0 +1,68 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+
5
+ from ai_agent.skill.models import SkillToolDecl
6
+
7
+ _FRONTMATTER_RE = re.compile(
8
+ r"\A---\r?\n(.*?)\r?\n---\r?\n?",
9
+ re.DOTALL,
10
+ )
11
+
12
+
13
+ def parse_tool_declarations(text: str) -> list[SkillToolDecl]:
14
+ """
15
+ 从 SKILL.md 全文解析 frontmatter 中的 tools 列表。
16
+
17
+ Args:
18
+ text: SKILL.md 全文
19
+
20
+ Returns:
21
+ 声明列表;无 tools 段时为空
22
+ """
23
+ match = _FRONTMATTER_RE.match(text)
24
+ if not match:
25
+ return []
26
+ return _parse_tools_block(match.group(1))
27
+
28
+
29
+ def _parse_tools_block(frontmatter: str) -> list[SkillToolDecl]:
30
+ lines = frontmatter.splitlines()
31
+ start = -1
32
+ for index, line in enumerate(lines):
33
+ if line.strip() == "tools:":
34
+ start = index + 1
35
+ break
36
+ if start < 0:
37
+ return []
38
+ decls: list[SkillToolDecl] = []
39
+ current_name = ""
40
+ current_handler = ""
41
+ for line in lines[start:]:
42
+ stripped = line.strip()
43
+ if not stripped:
44
+ continue
45
+ if stripped.startswith("- "):
46
+ if current_name and current_handler:
47
+ decls.append(
48
+ SkillToolDecl(name=current_name, handler=current_handler)
49
+ )
50
+ current_name = ""
51
+ current_handler = ""
52
+ item = stripped[2:].strip()
53
+ if item.startswith("name:"):
54
+ current_name = item.split(":", 1)[1].strip()
55
+ elif item.startswith("handler:"):
56
+ current_handler = item.split(":", 1)[1].strip()
57
+ continue
58
+ if stripped.startswith("name:"):
59
+ current_name = stripped.split(":", 1)[1].strip()
60
+ continue
61
+ if stripped.startswith("handler:"):
62
+ current_handler = stripped.split(":", 1)[1].strip()
63
+ continue
64
+ if not line.startswith((" ", "\t")):
65
+ break
66
+ if current_name and current_handler:
67
+ decls.append(SkillToolDecl(name=current_name, handler=current_handler))
68
+ return decls
ai_agent/tools.py ADDED
@@ -0,0 +1,123 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Awaitable, Callable
4
+ from dataclasses import dataclass
5
+ from typing import Any
6
+
7
+ from ai_agent.context import ToolInvocation
8
+
9
+
10
+ @dataclass
11
+ class Tool:
12
+ """可注册到 Agent 的工具;由库内执行并写回 ToolInvocation.answer。"""
13
+
14
+ name: str
15
+ description: str
16
+ parameters: dict[str, Any]
17
+ handler: Callable[..., Any]
18
+
19
+ def to_api(self) -> dict[str, Any]:
20
+ return {
21
+ "type": "function",
22
+ "function": {
23
+ "name": self.name,
24
+ "description": self.description,
25
+ "parameters": self.parameters,
26
+ },
27
+ }
28
+
29
+ async def run(self, arguments: dict[str, Any]) -> tuple[bool, str]:
30
+ """
31
+ 执行工具处理函数。
32
+
33
+ Returns:
34
+ 是否成功、写入 invocation.answer 的文本
35
+ """
36
+ try:
37
+ result = self.handler(**arguments)
38
+ if isinstance(result, Awaitable):
39
+ result = await result
40
+ return True, str(result)
41
+ except Exception as exc: # noqa: BLE001 — 工具边界统一收口
42
+ return False, str(exc)
43
+
44
+
45
+ class ToolRegistry:
46
+ """
47
+ 按来源分层维护工具,对外平铺为 OpenAI tools。
48
+
49
+ 层顺序:基础 → skill 管理 → 已启用 skill 子工具 → 额外注入;重名时报错。
50
+ """
51
+
52
+ def __init__(self, tools: list[Tool] | None = None) -> None:
53
+ self._base: dict[str, Tool] = {}
54
+ self._management: dict[str, Tool] = {}
55
+ self._skill: dict[str, Tool] = {}
56
+ self._extra: dict[str, Tool] = {}
57
+ self._flat: dict[str, Tool] = {}
58
+ if tools:
59
+ for tool in tools:
60
+ self._base[tool.name] = tool
61
+ self._rebuild_flat()
62
+
63
+ def set_base_tools(self, tools: list[Tool]) -> None:
64
+ """替换基础工具层(如 Harness 沙箱工具)。"""
65
+ self._base = {tool.name: tool for tool in tools}
66
+ self._rebuild_flat()
67
+
68
+ def set_management_tools(self, tools: list[Tool]) -> None:
69
+ """替换 skill 管理工具层。"""
70
+ self._management = {tool.name: tool for tool in tools}
71
+ self._rebuild_flat()
72
+
73
+ def set_skill_tools(self, tools: list[Tool]) -> None:
74
+ """替换当前已启用 skill 暴露的子工具层。"""
75
+ self._skill = {tool.name: tool for tool in tools}
76
+ self._rebuild_flat()
77
+
78
+ def set_extra_tools(self, tools: list[Tool]) -> None:
79
+ """替换额外注入工具(如 MCP)。"""
80
+ self._extra = {tool.name: tool for tool in tools}
81
+ self._rebuild_flat()
82
+
83
+ def register(self, tool: Tool) -> None:
84
+ """向额外层注册单个工具(与 ``set_extra_tools`` 同层,可覆盖同名)。"""
85
+ self._extra[tool.name] = tool
86
+ self._rebuild_flat()
87
+
88
+ def effective_tools(self) -> list[Tool]:
89
+ """当前合并后的全部工具实例。"""
90
+ return list(self._flat.values())
91
+
92
+ def api_tools(self) -> list[dict[str, Any]]:
93
+ return [tool.to_api() for tool in self._flat.values()]
94
+
95
+ def get(self, name: str) -> Tool | None:
96
+ return self._flat.get(name)
97
+
98
+ async def execute(self, invocation: ToolInvocation) -> None:
99
+ """执行一次调用并更新 invocation 的 answer / ok。"""
100
+ tool = self.get(invocation.tool_name)
101
+ if tool is None:
102
+ invocation.ok = False
103
+ invocation.answer = f"unknown tool: {invocation.tool_name}"
104
+ return
105
+ ok, text = await tool.run(invocation.arguments)
106
+ invocation.ok = ok
107
+ invocation.answer = text
108
+
109
+ def _rebuild_flat(self) -> None:
110
+ merged: dict[str, Tool] = {}
111
+ for layer_name, layer in (
112
+ ("base", self._base),
113
+ ("management", self._management),
114
+ ("skill", self._skill),
115
+ ("extra", self._extra),
116
+ ):
117
+ for name, tool in layer.items():
118
+ if name in merged:
119
+ raise ValueError(
120
+ f"工具名冲突: {name!r}({layer_name} 与已有层重复)"
121
+ )
122
+ merged[name] = tool
123
+ self._flat = merged
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-library-ai-agent
3
+ Version: 0.1.0
4
+ Requires-Python: >=3.10
5
+ Requires-Dist: mcp>=1.0
6
+ Requires-Dist: openai>=1.0
7
+ Requires-Dist: pydantic>=2.0
8
+ Provides-Extra: dev
9
+ Requires-Dist: pytest>=8.0; extra == 'dev'
10
+ Requires-Dist: python-dotenv>=1.0; extra == 'dev'
@@ -0,0 +1,62 @@
1
+ ai_agent/__init__.py,sha256=8F76hCsDdVh8RR9XuzYuDqFpDdTwMJo4pZRXTPHO4DY,1605
2
+ ai_agent/agent.py,sha256=YtKrsq7FU7k1Fmikh77YjhBUhnS-OqrNkVSBns9w1cM,3796
3
+ ai_agent/context.py,sha256=iWMD3OIXN35SWsAjlcdLY7Ehhjaoe6OcnubCt5BS53I,4587
4
+ ai_agent/json_extract.py,sha256=1z_T-Cz9LafPaA7TuZ82nwJIWkhjvzXq0IIDZq0koBA,1733
5
+ ai_agent/listener.py,sha256=zWTLnB-DdeqKX4yijmtIDuN1eZ3GeW76k-tZAC-B-8E,5213
6
+ ai_agent/llm.py,sha256=wquS2bnb6Bed84DeqThKgydtre4Q92p6ZWNRbqyoS6k,1002
7
+ ai_agent/llm_openai.py,sha256=1NtacqoL1_KNDA08pCdS-wDDBgk4U21TRXTFP2g6gx4,4139
8
+ ai_agent/loop.py,sha256=OqXovXCADW__anQWLX3a3Gl-K4QiiAnINe6FTo9iJ-o,4629
9
+ ai_agent/mcp_config.py,sha256=FrFdzWDX5LOGbnV2WKiDmyIoBhcqAn2LUNbk48m1QGY,1810
10
+ ai_agent/mcp_loader.py,sha256=vE5JFw2h8eYglYqpmoodfrF53w0w2xWzSdNreEoBGWY,3754
11
+ ai_agent/react_tool_turn.py,sha256=4eIT2e_2refTtPHS6fD_GkawA2UcJtCdylPsGxwOf_o,1514
12
+ ai_agent/tools.py,sha256=Zm4frKT2TskIUeBMbiwEgrIFHxFOhoLbEOnOdJy0thA,4314
13
+ ai_agent/app/__init__.py,sha256=WKbCB3qLOlnjaXA_3CRWcEhd5n9B8_VquaSzhYUySC0,254
14
+ ai_agent/app/_workspace.py,sha256=5sXJVk7pN6oAmo683_jV20X04NPhNuDwHGgKMYPfuZQ,3867
15
+ ai_agent/app/app.py,sha256=Ujd-nPteRaWWcZxCpPZ4ykh8ZBRIWH1aCgOh6PDLQLU,13037
16
+ ai_agent/app/harness_io.py,sha256=TU6N1wJLSdBfx8T6CRXB05DrhN7kAToCNXcAF84_M_0,3164
17
+ ai_agent/app/output_format.py,sha256=HL5Nx7PxYzvMP13d_cqvDLbY0ayHiRZjer07SHO-7m4,3612
18
+ ai_agent/app/packet.py,sha256=oouF2y6BTzVWkUxB-5nC3K-wFO6NOX8r9JoTFrxl0jA,1588
19
+ ai_agent/app/session.py,sha256=oW88fxYzjW7f3kGZIJn1xrL45n1y2GDqFcw4ckORDsE,14457
20
+ ai_agent/app/session_store.py,sha256=XBPAyjdMG0i2wK9l9s0W_rejEHHXQXaxpfvRhBPKJ8Q,2352
21
+ ai_agent/builtin_tools/__init__.py,sha256=0qKNyfLu5qvKwXY4KaG6oqZbPMkChZ-5EzMWXTKqrD0,541
22
+ ai_agent/builtin_tools/current_time.py,sha256=m66y7rzGEK5s9fB2zUdphEI7BUgLlqqxsbqCM_6_Rq0,1214
23
+ ai_agent/builtin_tools/pack.py,sha256=ZcI92hZqWe9BFx7cL9Hc3wQ64Enydy0-0QX60b8yUx8,583
24
+ ai_agent/builtin_tools/prefix.py,sha256=k0XOKMXLZHTxSQvhhTRU1YKmWx0zTqTcLTHkz3-O4iY,348
25
+ ai_agent/harness/__init__.py,sha256=E9KxDIRTs6kpijAj46aO3V3rUxyrAUQaWj50Zn0BYdk,71
26
+ ai_agent/harness/current_time.py,sha256=mWV1ro7KRSsvbS0Mj0ra-sxKuK0QSQUsknfkiIEhufs,721
27
+ ai_agent/harness/harness.py,sha256=UVEXDJXUW7uQNvUzSOyh-PjIUB00nd5ZSkwpk0P-96k,12208
28
+ ai_agent/harness/process.py,sha256=dFdF80ahZTC7AYwbYQMqVwbRfDKRqA8nGoQHw5-mDIU,3186
29
+ ai_agent/harness/prompts.py,sha256=jdfOZ_xca4A_9WkgmoYOAfNDzTlc87YsdNmOfYaY1ic,2261
30
+ ai_agent/harness/sandbox.py,sha256=ir19YqCTtytI9WjTJZzbUR4B7tMU2hhg7SxGvSK4GDo,4693
31
+ ai_agent/memory/__init__.py,sha256=7t0iTqF_TNri-uJu92zDIUHTqUBM2PB6GTu9ky3_rkg,256
32
+ ai_agent/memory/compression_work.py,sha256=jjravGtme7xc73HA3bCk3S7VZt1M93YKWVID3qTstdE,1376
33
+ ai_agent/memory/compressor.py,sha256=31pgoSSIlc3FcBpcUBFgsA0_WxX0TCWDkX3_efQYvQQ,12002
34
+ ai_agent/memory/config.py,sha256=gOMjFufb_62e0eglCHFowqDWn7sSCodgcMa5jubLCh8,1210
35
+ ai_agent/memory/context_builder.py,sha256=GHJ41OLFwjMixqEjzCpRgNgiScZFZNsRWwYjI6AryqM,2164
36
+ ai_agent/memory/memory_system.py,sha256=S0npW_HYoWdkl7In6Iy4G0l5sgkGlsuRfiwrherOrac,10446
37
+ ai_agent/memory/models.py,sha256=YSxkKe-z81IMV9cqWHQtZnsppfIqA_zem7NHAmAURq0,2376
38
+ ai_agent/memory/snapshot_merge.py,sha256=QQ8C4cZSq6YTCUIY0d5Vbdl3VeIxbPKOMmE28pt2ygE,5130
39
+ ai_agent/memory/store.py,sha256=z-2ST-3Ff7GMybucIPvVUSZafCftbZK1K8IGEsXjJ_M,3490
40
+ ai_agent/memory/worker.py,sha256=3Wui0h8KAtXxRpVVm9R2jIU_LRheJVr0l4xIb9UyIpk,7231
41
+ ai_agent/plan/__init__.py,sha256=JIUYfRuLwC2tr8EHrYmTyjD6hCRWdOmssZtd38Ew71s,426
42
+ ai_agent/plan/complete.py,sha256=kp8N36ueOKpid4r73l6MynunLKag6jaai9ZlDKgXWEk,2314
43
+ ai_agent/plan/delivery.py,sha256=imA_bVx2koq2Yh3JPHCNCJV8C67vmFSyoNTsG65S0e0,1462
44
+ ai_agent/plan/display.py,sha256=UJYsZt56bH76UnkzEQChBGCVYU_0kvEXaBQ9_qBcudc,1484
45
+ ai_agent/plan/models.py,sha256=5CfBymIGu8eLxxZneVbCtXSlueP3N3OQOlV-YNv9nfA,1590
46
+ ai_agent/plan/parse.py,sha256=KOPxup_ZkKap93T09dZ2r75D2MBJ4cZxdmWB7vzks8o,1169
47
+ ai_agent/plan/planner.py,sha256=GA2iAYjZSdaPeZO49EA315lbuE2RoZQCyabPCSm9kKU,4199
48
+ ai_agent/plan/runner.py,sha256=pRjw1o_LEFIXS1WG4RatopXZJDJyimWQ5MXipL3muuc,9473
49
+ ai_agent/rule/__init__.py,sha256=NBOekmeJSWo8yBqLCAqsNl6RGpmp-PExcsy1w-qXOrU,66
50
+ ai_agent/rule/rules.py,sha256=SRHbuaIW3oJlNz3VbwIeXuY3saxxvnaQa7ts3c_41PE,1269
51
+ ai_agent/skill/__init__.py,sha256=d15lKS6jd4ZO6UNaYP3UHHc2XVLsMjvdiwtTPc3Hfvo,226
52
+ ai_agent/skill/builtin_registry.py,sha256=7azSyzFA82MjXgf9jTz89nexExSZmQhtgkoaTlTGqM4,1658
53
+ ai_agent/skill/catalog.py,sha256=_FfOTXsfOV6i_bAf7sYZngKFTGRu-LaAjnoVuWDhE3Q,3068
54
+ ai_agent/skill/frontmatter.py,sha256=TcT534tfbTyVRDWK_2qrmub40SyNJ18o1G427PQ4EGU,2351
55
+ ai_agent/skill/manager.py,sha256=uecIs89xObK8ZFG9QKbjVqNUKFKzljkWu6Rutpnz77Q,18835
56
+ ai_agent/skill/models.py,sha256=GDh_LnU4XgACIt11iETdPCmOBUTiq7tA2f82j0BMj_c,835
57
+ ai_agent/skill/roots.py,sha256=XcpuXffTy3MMVIWnc10zwZ4mZjF6bDtQd9LSismoFg4,5485
58
+ ai_agent/skill/skill_kit.py,sha256=yaySLLD7VZu3hQ_GMOE5G7Yq5ax0EWlDIyfRvOZGrzs,2653
59
+ ai_agent/skill/tool_declarations.py,sha256=dSqiXRh-VgiUkDC4BLDzvCBNGcsTv1e_XMy6fmrIBCE,2093
60
+ python_library_ai_agent-0.1.0.dist-info/METADATA,sha256=niPh6IxfThtXDq_PK2OdHIBoI5SO4Cyy93kj-p6rvd8,284
61
+ python_library_ai_agent-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
62
+ python_library_ai_agent-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any