knowlyr-core 0.1.0__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.
@@ -0,0 +1,32 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ *.egg
7
+ dist/
8
+ build/
9
+ .eggs/
10
+
11
+ # Virtual environments
12
+ .venv/
13
+ venv/
14
+ env/
15
+
16
+ # IDE
17
+ .idea/
18
+ .vscode/
19
+ *.swp
20
+ *.swo
21
+
22
+ # Testing
23
+ .pytest_cache/
24
+ .coverage
25
+ htmlcov/
26
+
27
+ # Claude Code
28
+ CLAUDE.md
29
+
30
+ # OS
31
+ .DS_Store
32
+ Thumbs.db
@@ -0,0 +1,29 @@
1
+ Metadata-Version: 2.4
2
+ Name: knowlyr-core
3
+ Version: 0.1.0
4
+ Summary: Shared data models for knowlyr agent toolchain
5
+ Project-URL: Homepage, https://github.com/liuxiaotong/knowlyr-agent
6
+ Project-URL: Documentation, https://github.com/liuxiaotong/knowlyr-agent/tree/main/packages/core
7
+ Project-URL: Repository, https://github.com/liuxiaotong/knowlyr-agent
8
+ Project-URL: Issues, https://github.com/liuxiaotong/knowlyr-agent/issues
9
+ Author-email: Liu Kai <mrliukai@gmail.com>
10
+ License-Expression: MIT
11
+ Keywords: agent,code-agent,data-models,trajectory
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: pydantic>=2.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest; extra == 'dev'
26
+ Requires-Dist: ruff; extra == 'dev'
27
+ Description-Content-Type: text/plain
28
+
29
+ Shared data models for knowlyr agent toolchain.
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "knowlyr-core"
7
+ version = "0.1.0"
8
+ description = "Shared data models for knowlyr agent toolchain"
9
+ readme = {text = "Shared data models for knowlyr agent toolchain.", content-type = "text/plain"}
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Liu Kai", email = "mrliukai@gmail.com" }
14
+ ]
15
+ keywords = ["agent", "data-models", "trajectory", "code-agent"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: Science/Research",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
27
+ ]
28
+
29
+ dependencies = [
30
+ "pydantic>=2.0",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = ["pytest", "ruff"]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/liuxiaotong/knowlyr-agent"
38
+ Documentation = "https://github.com/liuxiaotong/knowlyr-agent/tree/main/packages/core"
39
+ Repository = "https://github.com/liuxiaotong/knowlyr-agent"
40
+ Issues = "https://github.com/liuxiaotong/knowlyr-agent/issues"
41
+
42
+ [tool.hatch.build.targets.wheel]
43
+ packages = ["src/knowlyrcore"]
44
+
45
+ [tool.ruff]
46
+ line-length = 100
47
+ target-version = "py310"
@@ -0,0 +1,59 @@
1
+ """knowlyr-core — 共享数据模型、领域配置与环境协议
2
+
3
+ 提供 knowlyr 生态各子包共用的基础数据类型、领域 Profile、
4
+ Gymnasium 风格 AgentEnv 协议和环境注册表。
5
+ """
6
+
7
+ __version__ = "0.1.0"
8
+
9
+ from knowlyrcore.domain import (
10
+ BROWSER_PROFILE,
11
+ CODING_PROFILE,
12
+ GENERIC_PROFILE,
13
+ DomainProfile,
14
+ OutcomeSpec,
15
+ ToolCategory,
16
+ ToolSpec,
17
+ get_domain_profile,
18
+ list_domain_profiles,
19
+ load_domain_profile,
20
+ )
21
+ from knowlyrcore.env import AgentEnv, EnvWrapper
22
+ from knowlyrcore.models import TaskInfo, ToolResult
23
+ from knowlyrcore.registry import (
24
+ EnvSpec,
25
+ list_envs,
26
+ make,
27
+ register,
28
+ spec,
29
+ )
30
+ from knowlyrcore.timestep import TimeStep
31
+
32
+ __all__ = [
33
+ # 数据模型
34
+ "TaskInfo",
35
+ "ToolResult",
36
+ # 领域配置
37
+ "DomainProfile",
38
+ "ToolCategory",
39
+ "ToolSpec",
40
+ "OutcomeSpec",
41
+ "CODING_PROFILE",
42
+ "BROWSER_PROFILE",
43
+ "GENERIC_PROFILE",
44
+ "get_domain_profile",
45
+ "load_domain_profile",
46
+ "list_domain_profiles",
47
+ # 环境协议
48
+ "AgentEnv",
49
+ "EnvWrapper",
50
+ "TimeStep",
51
+ # 注册表
52
+ "EnvSpec",
53
+ "register",
54
+ "make",
55
+ "list_envs",
56
+ "spec",
57
+ # 版本
58
+ "__version__",
59
+ ]
@@ -0,0 +1,205 @@
1
+ """领域配置 — DomainProfile / ToolCategory / ToolSpec / OutcomeSpec.
2
+
3
+ 通过 DomainProfile 声明工具分类和结果判定规则,让 pipeline 支持任意 tool-use agent 领域。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import json
9
+ from enum import Enum
10
+
11
+ from pydantic import BaseModel, Field
12
+
13
+
14
+ class ToolCategory(str, Enum):
15
+ """工具功能分类."""
16
+
17
+ READ = "read" # 读取/观察状态
18
+ WRITE = "write" # 修改状态
19
+ SEARCH = "search" # 搜索/发现
20
+ EXECUTE = "execute" # 执行命令
21
+ NAVIGATE = "navigate" # 切换上下文/位置
22
+ SUBMIT = "submit" # 提交/完成
23
+ THINK = "think" # 内部推理,无副作用
24
+
25
+
26
+ class ToolSpec(BaseModel):
27
+ """工具规格定义.
28
+
29
+ Attributes:
30
+ name: 工具主名称
31
+ category: 功能分类
32
+ stateful_key: 标识操作目标的参数名 (如 file_path / url / element_id)
33
+ aliases: 同一工具的别名列表
34
+ """
35
+
36
+ name: str
37
+ category: ToolCategory
38
+ stateful_key: str = ""
39
+ aliases: list[str] = Field(default_factory=list)
40
+
41
+
42
+ class OutcomeSpec(BaseModel):
43
+ """结果判定规格.
44
+
45
+ 定义如何从 outcome dict 中提取成功/分数信息。
46
+
47
+ Attributes:
48
+ success_field: 布尔成功字段名
49
+ score_field: 分数字段名 (如 tests_passed)
50
+ total_field: 总量字段名 (如 tests_total),与 score_field 配合计算比例
51
+ partial_credit_field: 手动部分得分字段名
52
+ """
53
+
54
+ success_field: str = "success"
55
+ score_field: str = ""
56
+ total_field: str = ""
57
+ partial_credit_field: str = "partial_credit"
58
+
59
+
60
+ class DomainProfile(BaseModel):
61
+ """领域配置.
62
+
63
+ 声明式地描述一个 agent 领域的工具集、结果判定、任务字段等。
64
+
65
+ Attributes:
66
+ domain: 领域标识 (如 coding / browser / data_analysis)
67
+ display_name: 可读名称
68
+ tools: 该领域的工具列表
69
+ outcome_spec: 结果判定规则
70
+ task_fields: 领域特有的任务字段 {字段名: 说明}
71
+ default_rubric_weights: 默认 rubric 权重覆盖
72
+ """
73
+
74
+ domain: str
75
+ display_name: str = ""
76
+ tools: list[ToolSpec] = Field(default_factory=list)
77
+ outcome_spec: OutcomeSpec = Field(default_factory=OutcomeSpec)
78
+ task_fields: dict[str, str] = Field(default_factory=dict)
79
+ default_rubric_weights: dict[str, float] = Field(default_factory=dict)
80
+
81
+
82
+ # ============================================================
83
+ # 内置领域 Profiles
84
+ # ============================================================
85
+
86
+ CODING_PROFILE = DomainProfile(
87
+ domain="coding",
88
+ display_name="Code Agent",
89
+ tools=[
90
+ ToolSpec(
91
+ name="read_file", category=ToolCategory.READ,
92
+ stateful_key="file_path",
93
+ aliases=["Read", "cat"],
94
+ ),
95
+ ToolSpec(
96
+ name="edit_file", category=ToolCategory.WRITE,
97
+ stateful_key="file_path",
98
+ aliases=["Edit", "sed", "write_file", "Write"],
99
+ ),
100
+ ToolSpec(
101
+ name="bash", category=ToolCategory.EXECUTE,
102
+ aliases=["Bash", "shell", "run"],
103
+ ),
104
+ ToolSpec(
105
+ name="grep", category=ToolCategory.SEARCH,
106
+ aliases=["Grep", "Glob", "find", "ls", "search"],
107
+ ),
108
+ ToolSpec(name="git", category=ToolCategory.EXECUTE),
109
+ ToolSpec(name="ipython", category=ToolCategory.EXECUTE),
110
+ ToolSpec(name="submit", category=ToolCategory.SUBMIT),
111
+ ToolSpec(name="finish", category=ToolCategory.SUBMIT),
112
+ ToolSpec(name="think", category=ToolCategory.THINK),
113
+ ],
114
+ outcome_spec=OutcomeSpec(
115
+ success_field="success",
116
+ score_field="tests_passed",
117
+ total_field="tests_total",
118
+ ),
119
+ task_fields={
120
+ "repo": "Git 仓库 (owner/repo)",
121
+ "base_commit": "基础 commit hash",
122
+ "test_command": "测试命令",
123
+ "language": "编程语言",
124
+ },
125
+ )
126
+
127
+ BROWSER_PROFILE = DomainProfile(
128
+ domain="browser",
129
+ display_name="Browser Agent",
130
+ tools=[
131
+ ToolSpec(
132
+ name="click", category=ToolCategory.WRITE,
133
+ stateful_key="element_id",
134
+ aliases=["tap"],
135
+ ),
136
+ ToolSpec(
137
+ name="type_text", category=ToolCategory.WRITE,
138
+ stateful_key="element_id",
139
+ aliases=["type", "fill", "input"],
140
+ ),
141
+ ToolSpec(
142
+ name="navigate", category=ToolCategory.NAVIGATE,
143
+ stateful_key="url",
144
+ aliases=["goto", "open_url"],
145
+ ),
146
+ ToolSpec(name="screenshot", category=ToolCategory.READ),
147
+ ToolSpec(
148
+ name="scroll", category=ToolCategory.NAVIGATE,
149
+ aliases=["scroll_up", "scroll_down"],
150
+ ),
151
+ ToolSpec(name="wait", category=ToolCategory.READ),
152
+ ToolSpec(name="extract_text", category=ToolCategory.READ),
153
+ ToolSpec(name="select", category=ToolCategory.WRITE),
154
+ ToolSpec(name="submit", category=ToolCategory.SUBMIT),
155
+ ],
156
+ outcome_spec=OutcomeSpec(success_field="success"),
157
+ task_fields={
158
+ "url": "目标 URL",
159
+ "expected_result": "预期结果描述",
160
+ },
161
+ )
162
+
163
+ GENERIC_PROFILE = DomainProfile(
164
+ domain="generic",
165
+ display_name="Generic Tool-Use Agent",
166
+ tools=[],
167
+ outcome_spec=OutcomeSpec(success_field="success"),
168
+ )
169
+
170
+ _BUILTIN_PROFILES: dict[str, DomainProfile] = {
171
+ "coding": CODING_PROFILE,
172
+ "browser": BROWSER_PROFILE,
173
+ "generic": GENERIC_PROFILE,
174
+ }
175
+
176
+
177
+ def get_domain_profile(domain: str) -> DomainProfile:
178
+ """获取内置领域 Profile.
179
+
180
+ Args:
181
+ domain: 领域标识 (coding / browser / generic)
182
+
183
+ Returns:
184
+ 对应的 DomainProfile,未找到时返回 GENERIC_PROFILE
185
+ """
186
+ return _BUILTIN_PROFILES.get(domain, GENERIC_PROFILE)
187
+
188
+
189
+ def load_domain_profile(path: str) -> DomainProfile:
190
+ """从 JSON 文件加载自定义 DomainProfile.
191
+
192
+ Args:
193
+ path: JSON 文件路径
194
+
195
+ Returns:
196
+ DomainProfile 实例
197
+ """
198
+ with open(path, "r", encoding="utf-8") as f:
199
+ data = json.load(f)
200
+ return DomainProfile.model_validate(data)
201
+
202
+
203
+ def list_domain_profiles() -> list[str]:
204
+ """列出所有内置领域名称."""
205
+ return list(_BUILTIN_PROFILES.keys())
@@ -0,0 +1,135 @@
1
+ """AgentEnv — Gymnasium 风格 Agent 环境协议.
2
+
3
+ 借鉴 Gymnasium Env + BrowserGym + AgentGym 的核心模式:
4
+ - reset() → TimeStep
5
+ - step(action) → TimeStep
6
+ - close()
7
+ - Wrapper 可组合
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from abc import ABC, abstractmethod
13
+ from typing import Any
14
+
15
+ from knowlyrcore.timestep import TimeStep
16
+
17
+
18
+ class AgentEnv(ABC):
19
+ """Agent 环境协议.
20
+
21
+ 所有环境(Docker 沙箱、浏览器、API mock 等)都实现此接口。
22
+ action 格式统一为 ``{"tool": "...", "params": {...}}``。
23
+
24
+ Usage::
25
+
26
+ env = SandboxEnv(config)
27
+ ts = env.reset(task=my_task)
28
+ while not ts.done:
29
+ action = agent.act(ts.observation)
30
+ ts = env.step(action)
31
+ env.close()
32
+ """
33
+
34
+ metadata: dict[str, Any] = {}
35
+ domain: str = "coding"
36
+
37
+ @abstractmethod
38
+ def reset(
39
+ self,
40
+ *,
41
+ task: Any | None = None,
42
+ seed: int | None = None,
43
+ ) -> TimeStep:
44
+ """重置环境到初始状态.
45
+
46
+ Args:
47
+ task: 任务信息 (TaskInfo 或兼容 dict)
48
+ seed: 随机种子(用于可复现性)
49
+
50
+ Returns:
51
+ 初始 TimeStep
52
+ """
53
+ ...
54
+
55
+ @abstractmethod
56
+ def step(self, action: dict[str, Any]) -> TimeStep:
57
+ """执行一步动作.
58
+
59
+ Args:
60
+ action: 动作字典,格式 {"tool": "...", "params": {...}}
61
+
62
+ Returns:
63
+ 执行后的 TimeStep
64
+ """
65
+ ...
66
+
67
+ def close(self) -> None:
68
+ """清理资源(默认空实现)."""
69
+
70
+ @property
71
+ def available_tools(self) -> list[str]:
72
+ """当前可用的工具/动作名列表."""
73
+ return []
74
+
75
+ @property
76
+ def unwrapped(self) -> AgentEnv:
77
+ """返回最内层非 Wrapper 环境."""
78
+ return self
79
+
80
+ def __enter__(self) -> AgentEnv:
81
+ return self
82
+
83
+ def __exit__(self, *args: Any) -> None:
84
+ self.close()
85
+
86
+ def __repr__(self) -> str:
87
+ return f"<{self.__class__.__name__} domain={self.domain!r}>"
88
+
89
+
90
+ class EnvWrapper(AgentEnv):
91
+ """环境包装器基类 — 对应 gymnasium.Wrapper.
92
+
93
+ 透传所有方法到内部环境,子类只需覆盖想要修改的方法。
94
+
95
+ Usage::
96
+
97
+ class MyWrapper(EnvWrapper):
98
+ def step(self, action):
99
+ ts = self.env.step(action)
100
+ ts.reward = compute_reward(ts)
101
+ return ts
102
+ """
103
+
104
+ def __init__(self, env: AgentEnv):
105
+ self.env = env
106
+
107
+ def reset(self, **kwargs: Any) -> TimeStep:
108
+ """透传 reset."""
109
+ return self.env.reset(**kwargs)
110
+
111
+ def step(self, action: dict[str, Any]) -> TimeStep:
112
+ """透传 step."""
113
+ return self.env.step(action)
114
+
115
+ def close(self) -> None:
116
+ """透传 close."""
117
+ self.env.close()
118
+
119
+ @property
120
+ def available_tools(self) -> list[str]:
121
+ """透传 available_tools."""
122
+ return self.env.available_tools
123
+
124
+ @property
125
+ def unwrapped(self) -> AgentEnv:
126
+ """递归返回最内层环境."""
127
+ return self.env.unwrapped
128
+
129
+ @property
130
+ def domain(self) -> str: # type: ignore[override]
131
+ """透传 domain."""
132
+ return self.env.domain
133
+
134
+ def __repr__(self) -> str:
135
+ return f"<{self.__class__.__name__}({self.env!r})>"
@@ -0,0 +1,59 @@
1
+ """共享数据模型 — ToolResult / TaskInfo."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+
10
+ class ToolResult(BaseModel):
11
+ """工具执行结果.
12
+
13
+ Attributes:
14
+ output: 标准输出内容
15
+ exit_code: 退出码 (0 表示成功)
16
+ error: 错误信息 (如果有)
17
+ """
18
+
19
+ output: str = ""
20
+ exit_code: int = 0
21
+ error: str | None = None
22
+
23
+ @property
24
+ def success(self) -> bool:
25
+ """执行是否成功."""
26
+ return self.exit_code == 0 and self.error is None
27
+
28
+
29
+ class TaskInfo(BaseModel):
30
+ """任务信息.
31
+
32
+ 描述一个待执行的任务,支持任意领域。coding 特有字段(repo/base_commit 等)
33
+ 保留供向后兼容,非 coding 领域可忽略。
34
+
35
+ Attributes:
36
+ task_id: 任务唯一标识
37
+ description: 任务描述
38
+ type: 任务类型 (如 bug_fix, feature, qa_check)
39
+ language: 编程语言 (coding 领域)
40
+ difficulty: 难度等级 (easy / medium / hard)
41
+ repo: 目标仓库 (coding 领域, 如 "owner/repo")
42
+ base_commit: 基础 commit hash (coding 领域)
43
+ test_command: 测试命令 (coding 领域)
44
+ domain: 所属领域 (coding / browser / generic / 自定义)
45
+ success_criteria: 成功判定描述 (领域无关)
46
+ metadata: 额外元数据
47
+ """
48
+
49
+ task_id: str = ""
50
+ description: str = ""
51
+ type: str = ""
52
+ language: str = ""
53
+ difficulty: str = ""
54
+ repo: str = ""
55
+ base_commit: str = ""
56
+ test_command: str = ""
57
+ domain: str = ""
58
+ success_criteria: str = ""
59
+ metadata: dict[str, Any] = Field(default_factory=dict)
@@ -0,0 +1,117 @@
1
+ """环境注册表 — knowlyr.make() 发现机制.
2
+
3
+ 借鉴 gymnasium.register() / gymnasium.make() 模式,
4
+ 命名规范沿用 "namespace/env-name" 格式。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass, field
10
+ from typing import Any
11
+
12
+ from knowlyrcore.env import AgentEnv
13
+
14
+
15
+ @dataclass
16
+ class EnvSpec:
17
+ """环境规格 — 对应 gymnasium.EnvSpec.
18
+
19
+ Attributes:
20
+ id: 环境标识 (如 "knowlyr/sandbox", "swebench/django-11099")
21
+ env_cls: 环境类
22
+ kwargs: 默认构造参数
23
+ domain: 领域标识
24
+ description: 环境描述
25
+ """
26
+
27
+ id: str
28
+ env_cls: type[AgentEnv]
29
+ kwargs: dict[str, Any] = field(default_factory=dict)
30
+ domain: str = "coding"
31
+ description: str = ""
32
+
33
+
34
+ _REGISTRY: dict[str, EnvSpec] = {}
35
+
36
+
37
+ def register(
38
+ id: str,
39
+ env_cls: type[AgentEnv],
40
+ *,
41
+ domain: str = "coding",
42
+ description: str = "",
43
+ **kwargs: Any,
44
+ ) -> None:
45
+ """注册一个环境.
46
+
47
+ Args:
48
+ id: 环境标识 (如 "knowlyr/sandbox")
49
+ env_cls: 环境类(必须继承 AgentEnv)
50
+ domain: 领域标识
51
+ description: 环境描述
52
+ **kwargs: 默认构造参数
53
+
54
+ Raises:
55
+ ValueError: 环境 ID 已注册
56
+ """
57
+ if id in _REGISTRY:
58
+ raise ValueError(f"环境已注册: {id!r}")
59
+ _REGISTRY[id] = EnvSpec(
60
+ id=id,
61
+ env_cls=env_cls,
62
+ kwargs=kwargs,
63
+ domain=domain,
64
+ description=description,
65
+ )
66
+
67
+
68
+ def make(id: str, **override_kwargs: Any) -> AgentEnv:
69
+ """创建环境实例 — 对应 gymnasium.make().
70
+
71
+ Args:
72
+ id: 环境标识
73
+ **override_kwargs: 覆盖默认构造参数
74
+
75
+ Returns:
76
+ AgentEnv 实例
77
+
78
+ Raises:
79
+ KeyError: 环境未注册
80
+ """
81
+ if id not in _REGISTRY:
82
+ available = ", ".join(sorted(_REGISTRY.keys())) or "(空)"
83
+ raise KeyError(f"未注册的环境: {id!r}。可用: {available}")
84
+ env_spec = _REGISTRY[id]
85
+ merged_kwargs = {**env_spec.kwargs, **override_kwargs}
86
+ return env_spec.env_cls(**merged_kwargs)
87
+
88
+
89
+ def list_envs(domain: str | None = None) -> list[str]:
90
+ """列出已注册的环境 ID.
91
+
92
+ Args:
93
+ domain: 按领域过滤(None 返回全部)
94
+
95
+ Returns:
96
+ 环境 ID 列表
97
+ """
98
+ if domain is None:
99
+ return sorted(_REGISTRY.keys())
100
+ return sorted(k for k, v in _REGISTRY.items() if v.domain == domain)
101
+
102
+
103
+ def spec(id: str) -> EnvSpec | None:
104
+ """获取环境规格.
105
+
106
+ Args:
107
+ id: 环境标识
108
+
109
+ Returns:
110
+ EnvSpec 或 None
111
+ """
112
+ return _REGISTRY.get(id)
113
+
114
+
115
+ def _clear_registry() -> None:
116
+ """清空注册表(仅用于测试)."""
117
+ _REGISTRY.clear()