ordin 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.
Files changed (159) hide show
  1. ordin-0.1.0/.env.example +7 -0
  2. ordin-0.1.0/.gitignore +10 -0
  3. ordin-0.1.0/AGENTS.md +52 -0
  4. ordin-0.1.0/PKG-INFO +111 -0
  5. ordin-0.1.0/README.md +100 -0
  6. ordin-0.1.0/benchmarks/context_stability.py +148 -0
  7. ordin-0.1.0/docs/adr/0001-agent-definition-instance.md +30 -0
  8. ordin-0.1.0/docs/adr/0002-task-dag-and-aggregation.md +31 -0
  9. ordin-0.1.0/docs/adr/0003-manifest-first-resources.md +32 -0
  10. ordin-0.1.0/docs/adr/0004-atomic-plan-revision.md +34 -0
  11. ordin-0.1.0/docs/adr/0005-agent-executor-contract.md +38 -0
  12. ordin-0.1.0/docs/adr/0006-domain-agent-release-discovery.md +38 -0
  13. ordin-0.1.0/docs/adr/0007-platform-independent-runtime.md +131 -0
  14. ordin-0.1.0/docs/adr/0008-supervisor-inbox.md +99 -0
  15. ordin-0.1.0/docs/architecture/context.md +156 -0
  16. ordin-0.1.0/docs/architecture/overview.md +84 -0
  17. ordin-0.1.0/docs/architecture/persistence.md +67 -0
  18. ordin-0.1.0/docs/architecture/resources.md +188 -0
  19. ordin-0.1.0/docs/architecture/runtime.md +121 -0
  20. ordin-0.1.0/docs/guides/clarification.md +80 -0
  21. ordin-0.1.0/docs/guides/custom-agent.md +102 -0
  22. ordin-0.1.0/docs/guides/custom-planner.md +103 -0
  23. ordin-0.1.0/docs/guides/domain-agents.md +93 -0
  24. ordin-0.1.0/docs/guides/platform-adapters.md +62 -0
  25. ordin-0.1.0/docs/guides/quickstart.md +96 -0
  26. ordin-0.1.0/docs/guides/tools-and-skills.md +228 -0
  27. ordin-0.1.0/docs/index.md +77 -0
  28. ordin-0.1.0/docs/modules/agent.md +122 -0
  29. ordin-0.1.0/docs/modules/artifact.md +97 -0
  30. ordin-0.1.0/docs/modules/context.md +143 -0
  31. ordin-0.1.0/docs/modules/llm.md +109 -0
  32. ordin-0.1.0/docs/modules/mission.md +111 -0
  33. ordin-0.1.0/docs/modules/runtime-ports.md +51 -0
  34. ordin-0.1.0/docs/modules/runtime.md +78 -0
  35. ordin-0.1.0/docs/modules/tool-and-skill.md +129 -0
  36. ordin-0.1.0/docs/reference/code-tree.md +203 -0
  37. ordin-0.1.0/docs/reference/configuration.md +107 -0
  38. ordin-0.1.0/docs/reference/events.md +87 -0
  39. ordin-0.1.0/docs/reference/public-api.md +365 -0
  40. ordin-0.1.0/examples/clarification.py +85 -0
  41. ordin-0.1.0/examples/csv_subagent.py +112 -0
  42. ordin-0.1.0/examples/custom_agent.py +81 -0
  43. ordin-0.1.0/examples/direct.py +72 -0
  44. ordin-0.1.0/examples/domain_agents/config.yaml +5 -0
  45. ordin-0.1.0/examples/domain_agents/office_csv/versions/1/adapter.py +69 -0
  46. ordin-0.1.0/examples/domain_agents/office_csv/versions/1/manifest.yaml +16 -0
  47. ordin-0.1.0/examples/domain_agents/office_csv/versions/1/schemas.py +7 -0
  48. ordin-0.1.0/examples/domain_agents/office_csv/versions/1/skills.py +22 -0
  49. ordin-0.1.0/examples/mission.py +76 -0
  50. ordin-0.1.0/examples/tool_registration.py +195 -0
  51. ordin-0.1.0/examples/tools_and_skills.py +130 -0
  52. ordin-0.1.0/notebooks/agent_playground.ipynb +1151 -0
  53. ordin-0.1.0/pyproject.toml +51 -0
  54. ordin-0.1.0/scripts/__init__.py +1 -0
  55. ordin-0.1.0/scripts/docs.py +269 -0
  56. ordin-0.1.0/src/arbor/__init__.py +5 -0
  57. ordin-0.1.0/src/arbor/agent/__init__.py +52 -0
  58. ordin-0.1.0/src/arbor/agent/catalog.py +134 -0
  59. ordin-0.1.0/src/arbor/agent/configuration.py +108 -0
  60. ordin-0.1.0/src/arbor/agent/definitions.py +184 -0
  61. ordin-0.1.0/src/arbor/agent/discovery.py +221 -0
  62. ordin-0.1.0/src/arbor/agent/models.py +39 -0
  63. ordin-0.1.0/src/arbor/agent/release.py +279 -0
  64. ordin-0.1.0/src/arbor/agent/routing.py +296 -0
  65. ordin-0.1.0/src/arbor/artifact/__init__.py +24 -0
  66. ordin-0.1.0/src/arbor/artifact/models.py +91 -0
  67. ordin-0.1.0/src/arbor/artifact/service.py +150 -0
  68. ordin-0.1.0/src/arbor/common/__init__.py +25 -0
  69. ordin-0.1.0/src/arbor/common/identity.py +7 -0
  70. ordin-0.1.0/src/arbor/common/json.py +63 -0
  71. ordin-0.1.0/src/arbor/common/registry.py +84 -0
  72. ordin-0.1.0/src/arbor/common/time.py +5 -0
  73. ordin-0.1.0/src/arbor/context/__init__.py +62 -0
  74. ordin-0.1.0/src/arbor/context/compression.py +504 -0
  75. ordin-0.1.0/src/arbor/context/engine.py +337 -0
  76. ordin-0.1.0/src/arbor/context/models.py +257 -0
  77. ordin-0.1.0/src/arbor/context/rendering.py +164 -0
  78. ordin-0.1.0/src/arbor/context/selection.py +83 -0
  79. ordin-0.1.0/src/arbor/context/service.py +441 -0
  80. ordin-0.1.0/src/arbor/conversation/__init__.py +9 -0
  81. ordin-0.1.0/src/arbor/conversation/models.py +38 -0
  82. ordin-0.1.0/src/arbor/conversation/service.py +96 -0
  83. ordin-0.1.0/src/arbor/hook/__init__.py +19 -0
  84. ordin-0.1.0/src/arbor/hook/lifecycle.py +112 -0
  85. ordin-0.1.0/src/arbor/hook/llm_call.py +25 -0
  86. ordin-0.1.0/src/arbor/llm/__init__.py +107 -0
  87. ordin-0.1.0/src/arbor/llm/execution.py +564 -0
  88. ordin-0.1.0/src/arbor/llm/interfaces.py +73 -0
  89. ordin-0.1.0/src/arbor/llm/models.py +206 -0
  90. ordin-0.1.0/src/arbor/llm/openai_compatible.py +212 -0
  91. ordin-0.1.0/src/arbor/llm/tool_parsing.py +158 -0
  92. ordin-0.1.0/src/arbor/llm/validation.py +52 -0
  93. ordin-0.1.0/src/arbor/memory/__init__.py +31 -0
  94. ordin-0.1.0/src/arbor/memory/models.py +82 -0
  95. ordin-0.1.0/src/arbor/memory/provider.py +46 -0
  96. ordin-0.1.0/src/arbor/memory/tools.py +135 -0
  97. ordin-0.1.0/src/arbor/mission/__init__.py +43 -0
  98. ordin-0.1.0/src/arbor/mission/aggregation.py +108 -0
  99. ordin-0.1.0/src/arbor/mission/evaluation.py +119 -0
  100. ordin-0.1.0/src/arbor/mission/models.py +100 -0
  101. ordin-0.1.0/src/arbor/mission/planning.py +237 -0
  102. ordin-0.1.0/src/arbor/mission/routing.py +125 -0
  103. ordin-0.1.0/src/arbor/mission/schemas.py +31 -0
  104. ordin-0.1.0/src/arbor/observability/__init__.py +17 -0
  105. ordin-0.1.0/src/arbor/observability/events.py +106 -0
  106. ordin-0.1.0/src/arbor/observability/models.py +18 -0
  107. ordin-0.1.0/src/arbor/runtime/__init__.py +214 -0
  108. ordin-0.1.0/src/arbor/runtime/agent_execution.py +627 -0
  109. ordin-0.1.0/src/arbor/runtime/authority.py +72 -0
  110. ordin-0.1.0/src/arbor/runtime/control.py +106 -0
  111. ordin-0.1.0/src/arbor/runtime/default_executor.py +389 -0
  112. ordin-0.1.0/src/arbor/runtime/engine.py +1017 -0
  113. ordin-0.1.0/src/arbor/runtime/execution.py +33 -0
  114. ordin-0.1.0/src/arbor/runtime/models.py +145 -0
  115. ordin-0.1.0/src/arbor/runtime/ports.py +252 -0
  116. ordin-0.1.0/src/arbor/runtime/resources.py +213 -0
  117. ordin-0.1.0/src/arbor/runtime/supervisor.py +1096 -0
  118. ordin-0.1.0/src/arbor/skill/__init__.py +14 -0
  119. ordin-0.1.0/src/arbor/skill/binding.py +151 -0
  120. ordin-0.1.0/src/arbor/skill/models.py +188 -0
  121. ordin-0.1.0/src/arbor/skill/registry.py +85 -0
  122. ordin-0.1.0/src/arbor/storage/__init__.py +3 -0
  123. ordin-0.1.0/src/arbor/storage/objects.py +21 -0
  124. ordin-0.1.0/src/arbor/testing/__init__.py +13 -0
  125. ordin-0.1.0/src/arbor/testing/backend.py +948 -0
  126. ordin-0.1.0/src/arbor/testing/fakes.py +22 -0
  127. ordin-0.1.0/src/arbor/testing/memory.py +143 -0
  128. ordin-0.1.0/src/arbor/testing/objects.py +28 -0
  129. ordin-0.1.0/src/arbor/testing/resources.py +39 -0
  130. ordin-0.1.0/src/arbor/tool/__init__.py +40 -0
  131. ordin-0.1.0/src/arbor/tool/binding.py +291 -0
  132. ordin-0.1.0/src/arbor/tool/execution.py +344 -0
  133. ordin-0.1.0/src/arbor/tool/models.py +109 -0
  134. ordin-0.1.0/src/arbor/tool/registry.py +102 -0
  135. ordin-0.1.0/tests/__init__.py +1 -0
  136. ordin-0.1.0/tests/fixtures/domain_agents/office_excel/versions/1/adapter.py +53 -0
  137. ordin-0.1.0/tests/fixtures/domain_agents/office_excel/versions/1/assets/template.txt +1 -0
  138. ordin-0.1.0/tests/fixtures/domain_agents/office_excel/versions/1/manifest.yaml +16 -0
  139. ordin-0.1.0/tests/fixtures/domain_agents/office_excel/versions/1/skills.py +20 -0
  140. ordin-0.1.0/tests/fixtures/domain_agents/office_excel/versions/1/tools.py +28 -0
  141. ordin-0.1.0/tests/runtime_helpers.py +113 -0
  142. ordin-0.1.0/tests/test_agent_execution.py +654 -0
  143. ordin-0.1.0/tests/test_agent_execution_and_runtime.py +1309 -0
  144. ordin-0.1.0/tests/test_artifacts.py +147 -0
  145. ordin-0.1.0/tests/test_common.py +36 -0
  146. ordin-0.1.0/tests/test_context_cache_stability.py +142 -0
  147. ordin-0.1.0/tests/test_context_rendering.py +1058 -0
  148. ordin-0.1.0/tests/test_conversation_and_context.py +229 -0
  149. ordin-0.1.0/tests/test_docs.py +279 -0
  150. ordin-0.1.0/tests/test_domain_agent_releases.py +669 -0
  151. ordin-0.1.0/tests/test_live_llm.py +390 -0
  152. ordin-0.1.0/tests/test_llm_call_pipeline.py +256 -0
  153. ordin-0.1.0/tests/test_memory.py +201 -0
  154. ordin-0.1.0/tests/test_mission_control.py +1269 -0
  155. ordin-0.1.0/tests/test_openai_compatible.py +44 -0
  156. ordin-0.1.0/tests/test_skill_tool_loading.py +437 -0
  157. ordin-0.1.0/tests/test_tool_call_parsing.py +71 -0
  158. ordin-0.1.0/tests/test_tools_and_hooks.py +100 -0
  159. ordin-0.1.0/uv.lock +996 -0
@@ -0,0 +1,7 @@
1
+ LLM_API_BASE=https://your-vllm-host.example/v1
2
+ LLM_API_KEY=replace-with-a-test-key
3
+ LLM_MODEL=/models/Qwen3.5-9B
4
+ LLM_TOOL_CALL_PARSER=hermes
5
+
6
+ # Optional: required only by PostgreSQL integration tests.
7
+ # TEST_DATABASE_URL=postgresql://user:password@localhost:5432/arbor_test
ordin-0.1.0/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .ty/
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+ .env
ordin-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,52 @@
1
+ # AGENTS.md
2
+
3
+ - 不要保留向后兼容性。应直接移除过时的路径,而不是增加兼容层、回退逻辑或迁移机制。
4
+ - 选择能够完整满足当前需求的最简单实现。避免引入推测性的抽象、配置和间接层。
5
+ - 以分层方式逐步扩展系统。先实现一个能够端到端工作的最小版本,再在已经可用的产品基础上逐步增加新能力。绝不要为了尚未完成的复杂性而牺牲一个已经能正常工作的产品。
6
+ - 保持组件模块化,并清晰分离各自的职责,高内聚,低耦合,合理抽象复用,组合优于继承,形成可维护和可拓展架构。
7
+ - 当成熟且维护良好的库能够降低整体复杂度或提高可靠性时,优先使用这些库。除非有明确理由,否则不要重复实现常见功能。
8
+ - 在自行实现功能或添加新依赖之前,优先充分利用项目中已有的依赖。不要在未检查相关文档和类型定义之前,就假设某个库不具备所需能力。
9
+ - 从长期角度做架构决策。不要接受只能暂时使用、之后注定需要被替换的权宜方案。
10
+
11
+ ## 文档结构与同步要求
12
+
13
+ - `README.md` 只维护项目定位、安装、最小示例和文档入口。
14
+ - `docs/architecture/` 是当前架构合同;`docs/modules/` 说明公开模块;`docs/guides/` 和
15
+ `examples/` 提供可运行用法;`docs/reference/` 保存生成参考;`docs/adr/` 保存长期架构决策。
16
+ - 已完成的实施计划不得作为当前文档长期保留。长期有效的决策应写入 ADR,实施过程由 Git、
17
+ Issue 或 PR 保存。
18
+ - `docs/reference/code-tree.md` 与 `docs/reference/public-api.md` 由 `scripts/docs.py` 生成,禁止
19
+ 手工编辑。文件树必须覆盖仓库中实际跟踪的源码、测试、Notebook、文档、示例和项目配置,且
20
+ 排除缓存、虚拟环境、构建产物和临时文件。
21
+ - 架构图和调用流程时序图统一使用 Mermaid,并使用代码中的真实包、类型、方法、状态和事件名。
22
+ - 模块文档必须说明职责、非职责、公开入口、核心模型、真实调用路径、最小示例、失败语义、事件、
23
+ 对应源码和对应测试。
24
+ - Markdown 中的 Python 示例必须能够编译;关键端到端示例必须放在 `examples/` 并由测试执行。
25
+
26
+ 每次开发任务开始时必须判断文档影响。发生以下任一变化时,必须在同一任务中更新文档:
27
+
28
+ - 新增、删除、移动或重命名模块和文件;
29
+ - 修改公开 API、构造参数、返回类型或异常语义;
30
+ - 修改 Runtime、Supervisor、Planner、Agent、Runner 或 Aggregator 的调用流程;
31
+ - 修改 Mission、Task、ExecutionPlan、AgentInstance、Context 或持久化模型;
32
+ - 新增或修改 RuntimeEvent、LLM operation、Tool、Skill、配置项、Artifact 或恢复语义;
33
+ - 新增关键扩展点或用户可见行为。
34
+
35
+ 如果代码变化不需要更新文档,最终结果必须明确说明原因,不得默认省略。
36
+
37
+ ## 开发任务完成前的必需校验
38
+
39
+ - 每次开发任务完成前,必须依次执行以下命令:
40
+
41
+ ```bash
42
+ uv run python scripts/docs.py --check
43
+ uv run pytest tests/test_docs.py
44
+ uv run ruff format .
45
+ uv run ruff check .
46
+ uv run ty check
47
+ uv run pytest
48
+ ```
49
+
50
+ - 只有生成文档无漂移、文档测试、格式化、静态检查、类型检查和完整测试全部通过后,才能将任务
51
+ 标记为完成。
52
+ - 如果检查因环境限制或与本次任务无关的既有问题无法通过,必须在最终结果中明确列出未通过的命令、错误原因和影响范围,不得省略或声称全部通过。
ordin-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.5
2
+ Name: ordin
3
+ Version: 0.1.0
4
+ Summary: Platform-independent runtime for centrally orchestrated agent execution
5
+ License: MIT
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: openai>=2.53.0
8
+ Requires-Dist: pydantic>=2.11.0
9
+ Requires-Dist: pyyaml>=6.0.2
10
+ Description-Content-Type: text/markdown
11
+
12
+ # Ordin Agent Runtime
13
+
14
+ Ordin 是一个模型中立、平台无关的 Python Agent Runtime。宿主平台提供已认证身份、持久化的用户消息、
15
+ Conversation 引用、不可变资源快照和运行时 Ports;Ordin 执行完整 Agent 链路:意图识别、
16
+ direct/clarify/Mission 路由、Task DAG、动态 sub-Agent、Context/LLM/Tool 循环、结果验收与最终聚合。
17
+
18
+ Ordin Core 不实现消息队列、Worker host、PostgreSQL 或具体对象存储。它定义领域模型、窄 Port、
19
+ CAS/原子提交/fencing/effect-ledger 合同,并在 `arbor.testing` 提供可执行的内存参考 Adapter。
20
+
21
+ PyPI distribution 名称是 `ordin`,当前稳定 Python 导入命名空间是 `arbor`。
22
+
23
+ ## 安装与校验
24
+
25
+ 从 PyPI 安装:
26
+
27
+ ```bash
28
+ pip install ordin
29
+ ```
30
+
31
+ 源码开发与完整校验:
32
+
33
+ ```bash
34
+ uv sync
35
+ uv run python scripts/docs.py --check
36
+ uv run pytest tests/test_docs.py
37
+ uv run ruff format .
38
+ uv run ruff check .
39
+ uv run ty check
40
+ uv run pytest
41
+ ```
42
+
43
+ ## 最小示例
44
+
45
+ 下面用内存 Adapter 模拟平台先持久化 `UserMessage`、再提交 `ExecutionRequest`。生产平台应以自己的
46
+ 事务存储和对象存储实现相同 Ports。
47
+
48
+ ```python
49
+ from arbor.agent import Agent
50
+ from arbor.common import Identity
51
+ from arbor.llm import LLMCallPipeline, LLMProfile
52
+ from arbor.mission import ConcatAggregator, SingleTaskPlanner
53
+ from arbor.observability import EventBroker
54
+ from arbor.runtime import Runtime
55
+ from arbor.testing import InMemoryObjectStore, InMemoryRuntimeBackend
56
+
57
+ backend = InMemoryRuntimeBackend()
58
+ events = EventBroker(backend)
59
+ llm_calls = LLMCallPipeline(
60
+ provider=my_llm_provider,
61
+ recorder=backend,
62
+ event_sink=events,
63
+ )
64
+ runtime = Runtime(
65
+ llm_calls=llm_calls,
66
+ events=events,
67
+ llm_profile=LLMProfile(id="private-model"),
68
+ backend=backend,
69
+ object_store=InMemoryObjectStore(),
70
+ direct_agent=Agent[None](name="direct", instructions="Answer the request."),
71
+ planner=SingleTaskPlanner(),
72
+ aggregator=ConcatAggregator(),
73
+ enable_memory_tools=False,
74
+ )
75
+
76
+ identity = Identity(user_id="u-1")
77
+ request = await backend.prepare_execution(
78
+ "实现一个可测试的分析流程",
79
+ identity=identity,
80
+ )
81
+ result = await runtime.execute(request, context=None)
82
+ ```
83
+
84
+ `Runtime.start()` 返回 direct/clarify 结果或 `MissionHandle`;`Runtime.execute()` 等待完整执行完成。
85
+ 两者都只接受平台已经装配好的 `ExecutionRequest`,不会接收并持久化原始用户消息。
86
+
87
+ 当同一 Branch 已有活跃 Execution 时,平台不应再创建并发 Execution,而应在同一事务追加
88
+ Conversation `UserMessage` 和 `SupervisorMessage`。Supervisor 会把消息分类为指导、目标修订、状态
89
+ 查询、取消、暂停、恢复或后继目标。内存参考 Adapter 的 `append_supervisor_text()` 展示了该原子入口。
90
+
91
+ ## 生产组合
92
+
93
+ 推荐使用 PostgreSQL 保存 Conversation、Execution/Mission、Plan/Task、command cursor、LLM call、
94
+ effect ledger 和 Artifact metadata,使用 S3/MinIO 等对象存储保存大字节。队列、lease、Worker 部署、
95
+ 认证、租户、配额和资源授权都由宿主平台负责。平台的 execution authority 必须在每次关键提交前
96
+ 检查所有权;外部 Tool 副作用仍需幂等键、对账和 `needs_attention`,不能宣称 exactly-once。
97
+
98
+ ## 文档
99
+
100
+ - [文档入口](docs/index.md)
101
+ - [架构总览](docs/architecture/overview.md)
102
+ - [Runtime 与 Supervisor](docs/architecture/runtime.md)
103
+ - [Ports 与生产 Adapter](docs/architecture/persistence.md)
104
+ - [快速开始](docs/guides/quickstart.md)
105
+ - [平台 Adapter 指南](docs/guides/platform-adapters.md)
106
+ - [代码树](docs/reference/code-tree.md) 与 [公开 API](docs/reference/public-api.md)
107
+ - [ADR-0007:平台无关 Runtime](docs/adr/0007-platform-independent-runtime.md)
108
+ - [ADR-0008:Supervisor Inbox](docs/adr/0008-supervisor-inbox.md)
109
+
110
+ 可运行示例位于 `examples/`;其中 `examples/csv_subagent.py` 展示平台冻结资源快照并构造
111
+ `ExecutionScope` 的完整离线路径。
ordin-0.1.0/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # Ordin Agent Runtime
2
+
3
+ Ordin 是一个模型中立、平台无关的 Python Agent Runtime。宿主平台提供已认证身份、持久化的用户消息、
4
+ Conversation 引用、不可变资源快照和运行时 Ports;Ordin 执行完整 Agent 链路:意图识别、
5
+ direct/clarify/Mission 路由、Task DAG、动态 sub-Agent、Context/LLM/Tool 循环、结果验收与最终聚合。
6
+
7
+ Ordin Core 不实现消息队列、Worker host、PostgreSQL 或具体对象存储。它定义领域模型、窄 Port、
8
+ CAS/原子提交/fencing/effect-ledger 合同,并在 `arbor.testing` 提供可执行的内存参考 Adapter。
9
+
10
+ PyPI distribution 名称是 `ordin`,当前稳定 Python 导入命名空间是 `arbor`。
11
+
12
+ ## 安装与校验
13
+
14
+ 从 PyPI 安装:
15
+
16
+ ```bash
17
+ pip install ordin
18
+ ```
19
+
20
+ 源码开发与完整校验:
21
+
22
+ ```bash
23
+ uv sync
24
+ uv run python scripts/docs.py --check
25
+ uv run pytest tests/test_docs.py
26
+ uv run ruff format .
27
+ uv run ruff check .
28
+ uv run ty check
29
+ uv run pytest
30
+ ```
31
+
32
+ ## 最小示例
33
+
34
+ 下面用内存 Adapter 模拟平台先持久化 `UserMessage`、再提交 `ExecutionRequest`。生产平台应以自己的
35
+ 事务存储和对象存储实现相同 Ports。
36
+
37
+ ```python
38
+ from arbor.agent import Agent
39
+ from arbor.common import Identity
40
+ from arbor.llm import LLMCallPipeline, LLMProfile
41
+ from arbor.mission import ConcatAggregator, SingleTaskPlanner
42
+ from arbor.observability import EventBroker
43
+ from arbor.runtime import Runtime
44
+ from arbor.testing import InMemoryObjectStore, InMemoryRuntimeBackend
45
+
46
+ backend = InMemoryRuntimeBackend()
47
+ events = EventBroker(backend)
48
+ llm_calls = LLMCallPipeline(
49
+ provider=my_llm_provider,
50
+ recorder=backend,
51
+ event_sink=events,
52
+ )
53
+ runtime = Runtime(
54
+ llm_calls=llm_calls,
55
+ events=events,
56
+ llm_profile=LLMProfile(id="private-model"),
57
+ backend=backend,
58
+ object_store=InMemoryObjectStore(),
59
+ direct_agent=Agent[None](name="direct", instructions="Answer the request."),
60
+ planner=SingleTaskPlanner(),
61
+ aggregator=ConcatAggregator(),
62
+ enable_memory_tools=False,
63
+ )
64
+
65
+ identity = Identity(user_id="u-1")
66
+ request = await backend.prepare_execution(
67
+ "实现一个可测试的分析流程",
68
+ identity=identity,
69
+ )
70
+ result = await runtime.execute(request, context=None)
71
+ ```
72
+
73
+ `Runtime.start()` 返回 direct/clarify 结果或 `MissionHandle`;`Runtime.execute()` 等待完整执行完成。
74
+ 两者都只接受平台已经装配好的 `ExecutionRequest`,不会接收并持久化原始用户消息。
75
+
76
+ 当同一 Branch 已有活跃 Execution 时,平台不应再创建并发 Execution,而应在同一事务追加
77
+ Conversation `UserMessage` 和 `SupervisorMessage`。Supervisor 会把消息分类为指导、目标修订、状态
78
+ 查询、取消、暂停、恢复或后继目标。内存参考 Adapter 的 `append_supervisor_text()` 展示了该原子入口。
79
+
80
+ ## 生产组合
81
+
82
+ 推荐使用 PostgreSQL 保存 Conversation、Execution/Mission、Plan/Task、command cursor、LLM call、
83
+ effect ledger 和 Artifact metadata,使用 S3/MinIO 等对象存储保存大字节。队列、lease、Worker 部署、
84
+ 认证、租户、配额和资源授权都由宿主平台负责。平台的 execution authority 必须在每次关键提交前
85
+ 检查所有权;外部 Tool 副作用仍需幂等键、对账和 `needs_attention`,不能宣称 exactly-once。
86
+
87
+ ## 文档
88
+
89
+ - [文档入口](docs/index.md)
90
+ - [架构总览](docs/architecture/overview.md)
91
+ - [Runtime 与 Supervisor](docs/architecture/runtime.md)
92
+ - [Ports 与生产 Adapter](docs/architecture/persistence.md)
93
+ - [快速开始](docs/guides/quickstart.md)
94
+ - [平台 Adapter 指南](docs/guides/platform-adapters.md)
95
+ - [代码树](docs/reference/code-tree.md) 与 [公开 API](docs/reference/public-api.md)
96
+ - [ADR-0007:平台无关 Runtime](docs/adr/0007-platform-independent-runtime.md)
97
+ - [ADR-0008:Supervisor Inbox](docs/adr/0008-supervisor-inbox.md)
98
+
99
+ 可运行示例位于 `examples/`;其中 `examples/csv_subagent.py` 展示平台冻结资源快照并构造
100
+ `ExecutionScope` 的完整离线路径。
@@ -0,0 +1,148 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import asyncio
5
+ import hashlib
6
+ import json
7
+ import os
8
+ from time import monotonic
9
+ from typing import Any
10
+
11
+ from arbor.common import canonical_json_bytes, ordered_json
12
+ from arbor.context import CharacterTokenEstimator
13
+ from arbor.llm import Message, LLMRequest, OpenAICompatibleLLMProvider
14
+
15
+ _STREAM_DOMAIN = b"arbor-rendered-message-stream-v1\0"
16
+
17
+
18
+ def rendered_message_stream(request: LLMRequest) -> bytes:
19
+ """Serialize only Arbor-rendered instructions/messages for prefix diagnostics."""
20
+
21
+ parts: list[bytes] = []
22
+ if request.instructions is not None:
23
+ parts.append(canonical_json_bytes(["instructions", request.instructions]))
24
+ parts.extend(
25
+ canonical_json_bytes(["message", message.model_dump(mode="json", exclude={"metadata"})])
26
+ for message in request.messages
27
+ )
28
+ encoded = bytearray(_STREAM_DOMAIN)
29
+ for part in parts:
30
+ encoded.extend(f"{len(part)}:".encode("ascii"))
31
+ encoded.extend(part)
32
+ return bytes(encoded)
33
+
34
+
35
+ def common_prefix_bytes(left: bytes, right: bytes) -> int:
36
+ for index, (left_byte, right_byte) in enumerate(zip(left, right, strict=False)):
37
+ if left_byte != right_byte:
38
+ return index
39
+ return min(len(left), len(right))
40
+
41
+
42
+ def component_hashes(request: LLMRequest) -> dict[str, str | None]:
43
+ tools = [
44
+ {
45
+ "name": tool.name,
46
+ "description": tool.description,
47
+ "input_schema": ordered_json(tool.input_schema),
48
+ }
49
+ for tool in request.tools
50
+ ]
51
+ return {
52
+ "ordered_tools_hash": hashlib.sha256(
53
+ canonical_json_bytes(["arbor-benchmark-tools-v1", tools])
54
+ ).hexdigest(),
55
+ "output_schema_hash": (
56
+ hashlib.sha256(
57
+ canonical_json_bytes(
58
+ [
59
+ "arbor-benchmark-output-schema-v1",
60
+ ordered_json(request.output_schema),
61
+ ]
62
+ )
63
+ ).hexdigest()
64
+ if request.output_schema is not None
65
+ else None
66
+ ),
67
+ }
68
+
69
+
70
+ def offline_report(requests: list[LLMRequest]) -> dict[str, Any]:
71
+ estimator = CharacterTokenEstimator()
72
+ streams = [rendered_message_stream(request) for request in requests]
73
+ adjacent = []
74
+ for index in range(1, len(streams)):
75
+ prefix_size = common_prefix_bytes(streams[index - 1], streams[index])
76
+ adjacent.append(
77
+ {
78
+ "left": index - 1,
79
+ "right": index,
80
+ "common_prefix_bytes": prefix_size,
81
+ "estimated_draft_common_prefix_tokens": estimator.estimate(
82
+ streams[index][:prefix_size].decode("utf-8", errors="ignore")
83
+ ),
84
+ }
85
+ )
86
+ return {
87
+ "metric": "arbor-rendered-message-common-prefix",
88
+ "requests": len(requests),
89
+ "adjacent": adjacent,
90
+ "components": [component_hashes(request) for request in requests],
91
+ }
92
+
93
+
94
+ async def live_report(request: LLMRequest, repeats: int) -> dict[str, Any]:
95
+ if os.getenv("RUN_LIVE_CONTEXT_CACHE_BENCHMARK") != "1":
96
+ raise RuntimeError("set RUN_LIVE_CONTEXT_CACHE_BENCHMARK=1 to enable Provider requests")
97
+ provider = OpenAICompatibleLLMProvider.from_env()
98
+ calls = []
99
+ for _ in range(repeats):
100
+ started = monotonic()
101
+ response = await provider.complete(request.model_copy(deep=True))
102
+ calls.append(
103
+ {
104
+ "duration_ms": (monotonic() - started) * 1000,
105
+ "input_tokens": response.usage.input_tokens,
106
+ "cached_input_tokens": response.usage.cached_input_tokens,
107
+ "deployment": response.provider_metadata.get("deployment"),
108
+ }
109
+ )
110
+ return {"metric": "provider-reported-cache-observation", "calls": calls}
111
+
112
+
113
+ def example_requests() -> list[LLMRequest]:
114
+ base = LLMRequest(
115
+ llm_profile_id=os.getenv("LLM_MODEL", "offline-model"),
116
+ instructions="Use the stable task contract.",
117
+ messages=[Message(role="user", content="task envelope")],
118
+ )
119
+ return [
120
+ base,
121
+ base.model_copy(
122
+ update={
123
+ "messages": [
124
+ *base.messages,
125
+ Message(role="assistant", content="first turn"),
126
+ ]
127
+ },
128
+ deep=True,
129
+ ),
130
+ ]
131
+
132
+
133
+ def main() -> None:
134
+ parser = argparse.ArgumentParser()
135
+ parser.add_argument("--live", action="store_true")
136
+ parser.add_argument("--repeats", type=int, default=2)
137
+ arguments = parser.parse_args()
138
+ requests = example_requests()
139
+ report = (
140
+ asyncio.run(live_report(requests[0], arguments.repeats))
141
+ if arguments.live
142
+ else offline_report(requests)
143
+ )
144
+ print(json.dumps(report, ensure_ascii=False, indent=2))
145
+
146
+
147
+ if __name__ == "__main__":
148
+ main()
@@ -0,0 +1,30 @@
1
+ # ADR-0001:统一 Agent 定义与执行实例
2
+
3
+ - 状态:Accepted;执行循环部分由 ADR-0005 修订
4
+ - 日期:2026-08-17
5
+
6
+ ## 上下文
7
+
8
+ 系统既需要复用 Excel、文档、演示文稿、Python 和网络检索等预定义专家 Agent,也需要
9
+ 在目录无明确匹配时,根据 Task 动态创建 sub_agent。如果为 Mission 子任务再引入一套平行的
10
+ 执行定义,Runner、Context、Hook、Tool、Skill 和持久化路径都会出现重复概念。
11
+
12
+ ## 决策
13
+
14
+ 1. `Agent` 是唯一完整执行定义,可来自 `AgentCatalog` 或 `DynamicAgentFactory`。
15
+ 2. `AgentManifest` 是 predefined Agent 的 implementation-free 搜索投影,不是第二套执行配置。
16
+ 3. `AgentInstance` 表示某个 `Agent` 执行某个 Task 的一次持久化实例,记录
17
+ Agent name/version/source/definition hash、branch、turn、status 和 CAS revision。
18
+ 4. `sub_agent` 只是 Mission 子任务 Agent 的角色称呼,不新增领域类型。
19
+ 5. predefined 和 dynamic Agent 使用相同的执行生命周期、Context、Tool、Skill、Hook、Artifact
20
+ 和 Result 路径;具体 Executor 合同由 [ADR-0005](0005-agent-executor-contract.md) 修订。
21
+
22
+ ## 结果
23
+
24
+ - Agent 目录可以为空,没有匹配时动态创建不是错误。
25
+ - 预定义 Agent 的增加只优化专业性、稳定性和资源组合,不需要修改 Supervisor 主链路。
26
+ - 恢复和诊断可通过 `agent_definition_hash` 识别实际执行定义。
27
+ - 不保留重复的子执行配置类型或兼容 API。
28
+
29
+ 参见 [架构总览](../architecture/overview.md) 和
30
+ [Agent、Tool 与 Skill 资源](../architecture/resources.md)。
@@ -0,0 +1,31 @@
1
+ # ADR-0002:统一 Task DAG 与唯一最终聚合
2
+
3
+ - 状态:Accepted
4
+ - 日期:2026-08-17
5
+
6
+ ## 上下文
7
+
8
+ 一般多步任务常表现为依赖链,复杂任务则包含可并发分支和运行中调整。将它们建模为两种
9
+ planning mode 会混淆计划拓扑和是否允许修订这两个维度。同时,子任务结果若直接回答原始
10
+ 请求,会造成重复综合、冲突结论和上下文泄漏。
11
+
12
+ ## 决策
13
+
14
+ 1. 所有 Mission 都使用 `ExecutionPlan.tasks` 构成的 DAG。
15
+ 2. 线性计划是每个 Task 依赖前一 Task 的 DAG;无依赖 Task 由 Supervisor 在
16
+ `max_concurrency` 内并发执行。
17
+ 3. Planner 负责目标拆解、deliverable、acceptance criteria、out-of-scope 和 dependencies,
18
+ 不指定 Agent 或硬 capability。
19
+ 4. Plan 自适应是 Supervisor 的独立、有上限能力,由 `max_plan_versions` 控制,不是
20
+ intent planning mode。
21
+ 5. sub_agent 只产生 Task-local `ResultEnvelope`;`TaskEvaluator` 先完成局部验收。
22
+ 6. `Aggregator.aggregate()` 是唯一 Mission 最终综合入口,把 Task 结果当作不可信数据。
23
+
24
+ ## 结果
25
+
26
+ - 一套 Plan 模型同时表达串行、并行和混合任务。
27
+ - Supervisor 仅执行依赖已完成的 ready Task,依赖失败会使下游 Task 变为 `BLOCKED`。
28
+ - Task 失败和验收拒绝进入相同 Plan 修订路径。
29
+ - Mission 目标不可在修订中静默改变;目标变更需要用户澄清。
30
+
31
+ 参见 [Runtime 与 Mission](../architecture/runtime.md)。
@@ -0,0 +1,32 @@
1
+ # ADR-0003:Manifest-first 资源目录与延迟加载
2
+
3
+ - 状态:Accepted
4
+ - 日期:2026-08-17
5
+
6
+ ## 上下文
7
+
8
+ 随着 predefined Agent、Tool 和 Skill 数量增长,如果 Runtime 启动时加载全部实现,或在每次调用中
9
+ 向模型发送全部 Tool schema 和 Skill 内容,初始化成本、Context token 和模型选择错误都会增长。
10
+ 资源授权同时已由上游宿主在注册前处理,不应在 Agent 中重复建立用户级或 Agent 级权限层。
11
+
12
+ ## 决策
13
+
14
+ 1. `AgentCatalog`、`ToolRegistry` 和 `SkillRegistry` 都先注册轻量 Manifest,支持 identity-checked
15
+ lazy loader。
16
+ 2. 所有成功注册 Tool/Skill 都视为宿主已确认的可用资源;Ordin 不做用户级或 Agent 级
17
+ 资源授权。
18
+ 3. `Agent.capabilities` 是稳定小写 semantic ID 组成的软搜索元数据,不是 Task 硬路由合同。
19
+ 4. `eager_tool_ids` 表示首轮预激活资源,不是 Tool 可用性上限。Agent 可通过 `search_tools`
20
+ 查找其他全局注册 Tool,并通过 `activate_tools` 在下一 turn 加载 native schema。
21
+ 5. Skill 首轮只提供 Manifest 和 preload sections,通过 `read_skill` 有上限地读取其他章节。
22
+ 6. Ordin 继续验证 ID、loader identity、Tool name/schema、Skill Tool 依赖、LLM Profile 协议和
23
+ Artifact provenance;这些是结构完整性,不是权限检查。
24
+
25
+ ## 结果
26
+
27
+ - Runtime 可先加载整个资源目录,但只为当前 Task 加载相关实现和 LLM-visible schemas。
28
+ - 空 AgentCatalog 不影响 Mission 通过动态 Agent 完成。
29
+ - 添加 Excel、文档、演示文稿、Python 或网络检索 Agent 时,只需增加注册资源,不修改 Supervisor 主链路。
30
+ - 首轮 Context 大小与已安装资源总数解耦。
31
+
32
+ 参见 [Agent、Tool 与 Skill 资源](../architecture/resources.md)。
@@ -0,0 +1,34 @@
1
+ # ADR-0004:Plan 修订使用 Store 级原子切换
2
+
3
+ - 状态:Accepted
4
+ - 日期:2026-08-17
5
+
6
+ ## 上下文
7
+
8
+ 当 Task 执行失败、被验收拒绝或依赖阻断时,Supervisor 可在版本上限内生成新 Plan。
9
+ 如果“标记旧 Task 为 `SUPERSEDED`”、“插入新 Plan/Task”和“切换
10
+ `Mission.current_plan_version`”是三组独立写入,任一失败都可使 Mission 留在无法继续的混合状态。
11
+
12
+ ## 决策
13
+
14
+ 1. `ExecutionPlan` 版本 append-only,同 Mission/version 不允许覆盖。
15
+ 2. 初始 Plan 通过 `RuntimeStore.save_plan()` 单次创建。
16
+ 3. 修订 Plan 统一通过
17
+ `RuntimeStore.save_revised_plan(user_id, previous_plan, revised_plan)` 提交。
18
+ 4. 该操作在一个 Store 原子区间内:
19
+ - 锁定并校验当前 Plan version;
20
+ - 校验新版本连续且保留全部 completed Tasks;
21
+ - 插入新 Plan 和新 Tasks;
22
+ - 标记旧版本中未完成 Tasks 为 `SUPERSEDED`;
23
+ - 切换 `Mission.current_plan_version`。
24
+ 5. `MemoryStore` 使用单一 lock,`PsycopgStore` 使用单一事务和行锁。
25
+ 6. `task.superseded` 和 `mission.plan_revised` 事件只在 Store commit 成功后发送。
26
+
27
+ ## 结果
28
+
29
+ - 修订成功时,新 Plan、Task 状态和 current version 对读取者同时可见。
30
+ - 修订失败时,旧 Plan 仍保持可解释状态,不提前破坏旧 Tasks。
31
+ - completed Task 结果可在新 Plan 中复用,不重复执行。
32
+ - RuntimeEvent 仍不与 Store Adapter 形成跨系统事务;Store 状态是恢复时的真相。
33
+
34
+ 参见 [持久化与恢复边界](../architecture/persistence.md)。
@@ -0,0 +1,38 @@
1
+ # ADR-0005:统一 Agent 生命周期与可替换 Executor
2
+
3
+ - 状态:Accepted
4
+ - 日期:2026-08-18
5
+
6
+ ## 上下文
7
+
8
+ `Agent` 当前描述 instructions、Tool、Skill、输出类型和执行限制,`Runner` 同时拥有
9
+ AgentInstance 生命周期与固定的 Context/LLM/Tool turn loop。下游领域 Agent 可能已经有自己的
10
+ 执行循环,但仍必须遵守 Ordin 的 Task、状态、取消、审计、Artifact 和结果合同。
11
+
12
+ ## 决策
13
+
14
+ 1. `AgentExecutionCoordinator` 是 AgentInstance 生命周期的唯一所有者,负责状态、CAS、Hook、
15
+ timeout、取消、事件、usage、Artifact provenance、输出校验和 `RunResult`。
16
+ 2. `AgentExecutor` 只执行一次 Task attempt 的领域循环,通过受控 `AgentExecutionSession` 使用
17
+ canonical Task、dependency results、input Artifacts、Context、LLM、Tool、Artifact 和统一
18
+ checkpoint 能力。
19
+ 3. `DefaultAgentExecutor` 实现当前 Ordin 的 Context/LLM/Tool 多轮循环;领域实现可以提供其他
20
+ Executor,但不能直接修改 Mission、Task、AgentInstance 或 Store。
21
+ 4. Executor 接收 canonical `Task`。领域代码可以派生结构化领域输入,但不能改写 Mission goal、
22
+ Task instruction、deliverable、acceptance criteria、dependencies 或 out-of-scope。
23
+ 5. 所有 Executor 都返回统一 `AgentExecutionOutcome`,最终由 Coordinator 生成
24
+ `ResultEnvelope` 和 `RunResult`。
25
+ 6. 不保留旧 `Runner` 兼容入口;迁移完成后统一使用 Coordinator。
26
+ 7. Executor 即使不主动轮询,也会被 Coordinator 与 cancellation/lease guard 竞速;失去 Worker
27
+ 所有权时不得再提交 AgentInstance 或事件。
28
+ 8. Session 不暴露可直接调用的 FunctionTool;默认与自定义 Executor 都通过
29
+ `session.execute_tools()` 进入同一 Policy、Hook、Artifact 和 invocation ledger 边界。
30
+
31
+ ## 结果
32
+
33
+ - 预定义、动态和下游领域 Agent 共享相同状态、审计和结果语义。
34
+ - 自定义循环不能绕过 Runtime Policy、取消和持久化边界。
35
+ - `Agent` 保持模型中立,Executor 的实现身份进入版本化领域 Agent release hash。
36
+
37
+ 参见 [架构总览](../architecture/overview.md) 和
38
+ [Runtime 与 Mission](../architecture/runtime.md)。
@@ -0,0 +1,38 @@
1
+ # ADR-0006:版本化领域 Agent Release 与受控发现
2
+
3
+ - 状态:Accepted
4
+ - 日期:2026-08-18
5
+
6
+ ## 上下文
7
+
8
+ 应用需要把内部团队维护的 Excel、PPT、ERP 和其他领域 Agent 快速接入 Ordin,并允许同一逻辑
9
+ Agent 的多个历史版本共存。目录约定应提高开发效率,但不能让文件遍历顺序、隐式覆盖或任意
10
+ Python import 决定运行行为。
11
+
12
+ ## 决策
13
+
14
+ 1. 一个不可变版本目录构建一个 `DomainAgentRelease`,包含 Agent 定义、Executor、不可变
15
+ `ExecutorConfig`、私有 Tool、共享 Tool、release-local Skill、输出合同、资产摘要和完整 bundle
16
+ hash。hash 覆盖 Agent metadata,且 release 与 Agent 必须声明相同 `output_type`。
17
+ 2. 领域代码位于受控根目录的 `<agent>/versions/<version>/`,使用 implementation-free Manifest
18
+ 和固定 `adapter.py:build()` 入口。
19
+ 3. Scanner 使用安全 YAML 解析和严格模型校验,只扫描约定路径,拒绝路径逃逸、重复 release、
20
+ name/version 不一致和未知字段。
21
+ 4. Scanner 不激活 Agent、不授予用户权限,也不边扫描边修改运行中的 Registry;所有 release
22
+ 通过验证后生成不可变 `CodeReleaseCatalog`。
23
+ 5. 同一 `(agent_name, version)` 的内容不可原地改变。bundle hash 覆盖 Manifest、Executor 合同、
24
+ Tool schema/执行属性、Skill version/content hash、输出 schema 和资产 bytes。
25
+ 6. 配置和 adapter 是 release 定义真相;数据库 release 行是不可变投影;数据库 Catalog 保存
26
+ active version;用户 grant 保存可用逻辑 Agent;submission snapshot 保存实际执行版本。
27
+ 7. 私有 Tool 随 release 绑定。只有明确允许同一 submission 内其他 Agent 发现的能力才进入共享
28
+ ToolRegistry;重复 semantic ID/name 继续显式失败,不实现 Layer 覆盖语义。
29
+ 8. `active_releases()` 只构建根配置启用的目标版本;Scope 建立前重新验证内存 identity 与磁盘文件,
30
+ 组装后 seal Agent、Tool、Skill Registry。Agent 不得隐式绑定其他 release 拥有的 Skill。
31
+
32
+ ## 结果
33
+
34
+ - 新目录可以被发现,但不会自动启用或授权。
35
+ - 运行和恢复可以验证精确版本及完整资源身份。
36
+ - 目录结构服务开发体验,机器行为由严格 Release 合同决定。
37
+
38
+ 参见 [Agent、Tool 与 Skill 资源](../architecture/resources.md)。