Metadata-Version: 2.4
Name: fairlead
Version: 0.12.1
Summary: A composable, auditable evidence and governance kernel for LLM and agent applications.
Keywords: agent,audit,evidence,governance,llm,pydantic-ai
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Dist: pydantic>=2.12,<3
Requires-Dist: pydantic-ai-slim[anthropic]==2.36.0 ; extra == 'anthropic'
Requires-Dist: pydantic-ai-slim[google]==2.36.0 ; extra == 'google'
Requires-Dist: pydantic-ai-harness>=0.27,<0.28 ; extra == 'harness'
Requires-Dist: pydantic-ai-slim==2.36.0 ; extra == 'harness'
Requires-Dist: pydantic-ai-slim[openai]==2.36.0 ; extra == 'openai-compatible'
Requires-Dist: pydantic-ai-slim==2.36.0 ; extra == 'pydantic-ai'
Requires-Dist: pydantic-ai-slim[zai]==2.36.0 ; extra == 'zai'
Requires-Python: >=3.12
Project-URL: Changelog, https://github.com/gugia/fairlead/blob/main/CHANGELOG.md
Project-URL: Homepage, https://github.com/gugia/fairlead
Project-URL: Issues, https://github.com/gugia/fairlead/issues
Project-URL: Repository, https://github.com/gugia/fairlead.git
Provides-Extra: anthropic
Provides-Extra: google
Provides-Extra: harness
Provides-Extra: openai-compatible
Provides-Extra: pydantic-ai
Provides-Extra: zai
Description-Content-Type: text/markdown

# Fairlead

Fairlead 是面向 LLM/Agent 应用的中间件中立证据与治理内核。它不重写 Agent loop，也不接管业务；它把
跨项目最容易漂移、最需要追溯的事实固定成小而严格的契约：执行绑定、Prompt/Context revision、逻辑
Run、实际 Attempt、有效调用观察、usage、审计快照和安全错误。

当前源码 release train 为 `0.12.1`。项目仍处于 Alpha/pre-1.0；0.12 是一次明确的硬切基线，不读取或
迁移旧 PostgreSQL 行、测试数据、core v1 JSON、reader 或 fixture。现有 core versioned envelopes 保持
类名并直接要求 `schemaVersion=2`。达到 1.0 前，Fairlead 不承诺跨 minor 向后兼容；它通过小而清晰的当前 API、严格
门禁和真实业务提炼来减少未来改动，而不是为尚未采用的旧设计保留兼容层。

## 为什么存在

Pydantic AI 和 Pydantic AI Harness 已经提供 Agent 执行、工具、结构化输出、Capability、消息历史、
通用 memory/compaction、预算和步骤持久化。Fairlead 不把这些能力包装成第二套框架。

| 层 | 拥有的语义 |
| --- | --- |
| 业务应用 | Prompt 内容、业务输入/输出、权限、工具副作用、事实优先级、评测、保留授权与用户协议 |
| Pydantic AI / Harness | Agent loop、Model/Provider、Capability、工具/输出重试、消息历史、通用执行机制 |
| Fairlead core | `ExecutionBindingRef`、Run/Attempt Journal、幂等、unknown outcome、usage 与审计投影 |
| Fairlead Pydantic AI integration | ProviderConfig、ExecutionPolicy、AdapterQualification 三个配置域、由三者闭合的不可变 ResolvedExecutionBinding 及有效调用观察；当前类名使用 `*Ref`/`*RevisionV1`/`V1` |

现行总决策见 [ADR-0021](https://github.com/gugia/fairlead/blob/v0.12.1/docs/architecture/0021-pre-1.0-hard-cut-and-execution-evidence.md)，
产品边界见 [当前需求](https://github.com/gugia/fairlead/blob/v0.12.1/docs/product/requirements.md) 和
[能力所有权](https://github.com/gugia/fairlead/blob/v0.12.1/docs/product/capability-ownership.md)。

## 一个 distribution，两个顶层包

Fairlead 只发布一个 `fairlead` wheel/sdist，不建立第二个 distribution、workspace 或版本列车。同一
wheel 包含两个普通顶层包：

- `fairlead`：provider-neutral core，只要求 Pydantic；
- `fairlead_pydantic_ai`：Pydantic AI 2.36.0 integration，不从 core 自动导入。

纯 core 安装：

```bash
uv add fairlead
```

需要 Pydantic AI integration 时显式安装 extra：

```bash
uv add "fairlead[pydantic-ai]"
```

integration 只支持精确 `pydantic-ai-slim==2.36.0`，不支持 Pydantic AI 1.x，也不对未验证的其他版本
做动态猜测。纯 core 环境不会安装 Pydantic AI、Harness 或 provider SDK；即使同一 wheel 包含
`fairlead_pydantic_ai` 源码，`import fairlead` 也不会加载 optional integration。

0.12 删除旧 `fairlead.experimental.pydantic_ai` 且不提供转发。provider-specific doctors 暂留
experimental，但改为使用 `fairlead_pydantic_ai` contracts；它们没有跨 minor 兼容承诺。

支持 Python 3.12、3.13 和 3.14。实际依赖以当前 `pyproject.toml`、lock 和 CI 为准。

## 执行绑定

业务在任何 provider I/O 前先由 integration 解析完整执行配置：

```text
ProviderConfig
  + ExecutionPolicy
  + AdapterQualification
  + 应用选择的 Model / Agent / Capability
                  │
                  ▼
       ResolvedExecutionBindingV1
                  │ canonical bytes + sha256
                  ▼
       ExecutionBindingRef (core)
```

core `ModelTarget.defaults` 只保留 `temperature` 和 `max_output_tokens`。`ReasoningEffort` 以及旧
`reasoning_effort`/`timeout_seconds`/`max_retries` 配置面已硬切删除，不提供 alias。thinking
以及 HTTP transport 的 connect/read/write/pool timeout、transport retry 由 ProviderConfig 唯一表达；
model request/Agent/Capability timeout 由 ExecutionPolicy 唯一表达；core 不与 integration 重复拥有
这些含义。

`ResolvedExecutionBindingV1` 属于 `fairlead_pydantic_ai`，描述实际获准使用的 provider/model、策略、
adapter qualification 和相关 revision；它不能包含凭据、client 或运行时对象。`ExecutionBindingRef`
属于 core，只保存 schema/canonicalizer/binding identity、摘要和可选受控 Artifact 引用，core 不解释
integration 正文。

revision 按语义域独立推进：endpoint/API mode、权限主体、project/region、transport timeout/retry 或
thinking 改变时更新 ProviderConfig；model request/Agent/Capability policy 改变时更新 ExecutionPolicy；
上游版本、Provider/Model 类或有效 Profile 资格改变时更新 AdapterQualification；provider/model name、
声明能力或 provider-neutral defaults 改变时更新 ModelTarget。同一权限主体轮换 API key value 不产生新
ProviderConfig revision，也不保存 key；Prompt、Context 与 tool Schema 只更新自身引用和 RunIntent。

同一 `ExecutionBindingRef` 必须在 provider I/O 前进入 `RunIntent`、幂等比较和 Attempt identity。
binding 漂移、qualification 不匹配或上游版本不受支持时，必须在 provider I/O 前失败关闭。

## 两类权威证据

Fairlead 明确维护两类范围不同、不能互相替代的权威证据。

### 意图与生命周期证据

core `RunJournal` 记录：

- 冻结了哪个 `ExecutionBindingRef`、Prompt、Context、Schema 和业务幂等意图；
- Run/Attempt 的开始、成功、失败、取消、usage 与连续 revision/sequence；
- queued/running 命中、冲突和 unknown outcome 的恢复判断。

Journal 是生命周期权威。幂等命中正在执行或结果未知的 Run 时，不得再次调用 provider；无法判断请求
是否到达远端时，不得伪造成已失败、零 usage 或可安全重放。

### 有效调用证据

`fairlead_pydantic_ai` 当前内置 runtime 自动记录：

- 最终 Pydantic AI `ModelRequest` 的受控语义投影；
- outermost Capability observation hook 的 `before-run`/`after-run`/`run-error` 时点与
  capability-chain identity；该 receipt 不证明某个应用 Capability 已 short-circuit 或变换请求/结果；

它还公开 `ObservedHttpRequestProjectionV1`、对应 receipt 和工厂，作为采用方 instrumented transport 的
低敏证据契约。当前 stock runtime/provider resource **尚未安装 transport hook**，
`PydanticAIEvidenceSink` 也不会自动收到物理 attempt receipt；因此当前启用非零 transport retry 会在
provider I/O 前以 `transport-retry-installation-unqualified` 失败关闭。

只有采用项目实际安装并资格验证该 hook 后，transport 开始事件才能命名为
`observed_http_request_projection`。它只证明应用侧观察到请求投影进入本地 transport，**不证明 provider
已收到、接受、处理或计费**。一个逻辑 Fairlead Attempt 可以包含多个物理 HTTP attempts；未安装 hook
时该层是 `not-qualified`，不能用 ModelRequest receipt、零计数或工厂单测替代物理观察。

两类证据都可被 Journal 持久化或引用，但 integration 不能重写 lifecycle，core 也不能从本地观察推断
远端事实。日志、指标、trace、SSE 和 Redis hint 均是可丢失投影，不是第三个权威源。
当前 `PydanticAIEvidenceSink` 只接收已规范化的低敏 ModelRequest 与 Capability receipts，不拥有 Journal
生命周期，也不接收 transport receipt；内存实现仅供 reference/测试，不声明耐久性。

## 最小采用链路

Fairlead 可以逐段接入已有 Agent 项目：

1. 应用给出业务 target、Prompt/Context/Schema revision 和允许的执行策略；
2. integration 用 Pydantic AI 2.36.0 public API 解析并资格校验 `ResolvedExecutionBindingV1`；
3. 生成 `ExecutionBindingRef`，在 provider I/O 前与 Run 意图一起原子写入 Journal；
4. 先持久化 Attempt started，再执行官方 Agent/Model；
5. integration 自动记录 ModelRequest 与 Capability observation；采用项目若需要物理 retry/attempt
   证据，另行安装并资格验证 instrumented transport hook；
6. 已完成响应的 usage 归属到精确 Attempt；失败、取消和 unknown outcome 保持不同；
7. 使用公共 reducer、AuditBundle 和 metering 投影验证内部一致性。

Journal、Harness StepPersistence、业务 ResultStore 和 ArtifactStore 保存不同事实。采用项目必须明确每份
事实的 owner、事务边界、恢复语义和保留政策，不能用双写制造两个生命周期权威。

## Context、压缩与预算

`ContextBundle`/receipt 记录业务应用已经授权的来源、排序、选择、裁切、脱敏、摘要和 producer
lineage。Fairlead 不替业务读取正文或决定该丢什么，也不复制 Pydantic AI/Harness 的 MessageHistory
和通用 compaction。

模型生成的业务摘要必须是独立 Run/Attempt/Result，再由 child Bundle 引用；通用 history compaction
可以委托上游，但不能冒充同一类业务证据。

以下事实必须分开：事前业务预算、Context token 估算、框架执行限额、逻辑 Attempt、已安装 hook 实际
观察到的物理 HTTP attempt、已完成响应的 usage、成本估算和供应商账单。未安装 hook 时物理 attempt
资格为 `not-qualified`，不能填零。`CostEstimate` 不是账单。

## Result 正文生命周期

ResultStore 只属于 PostgreSQL reference/application，不是 core 端口。当前 Result 正文默认在保存后
30 天逻辑到期，但这个“默认”也必须由 Operation 已绑定的 approved exact configuration 中
required `result-retention-policy` ref 显式选中，不存在缺省 ref 时的隐式回退。采用项目可以用同一必需
ref 机制选择其他正 TTL 或
`retain_until_explicit_delete`。后者只表示没有计划到期，不表示不可删除或法律意义的永久保存。

0.12 不保留 v0.10 grandfather、旧 policy/configuration reader 或旧 migration prefix 升级路径。旧开发
PostgreSQL、测试行和制品必须删除并从当前空基线重建。逻辑到期后普通读取立即拒绝正文，
即使 janitor 尚未物理清理；Result 元数据、hash、size、
policy 和 purge receipt 长期保留。`record_body`、`output_body` 与相同 output Artifact body 属于同一
保留域并在同一清理事务处理。

详见 [Result retention 契约](https://github.com/gugia/fairlead/blob/v0.12.1/docs/contracts/result-retention.md)
和 [ADR-0021](https://github.com/gugia/fairlead/blob/v0.12.1/docs/architecture/0021-pre-1.0-hard-cut-and-execution-evidence.md)。

## Schema 与当前支持面

0.12 的现有 core contracts 位于 `fairlead/schemas/v2/`；`RunEvent`、`RunAuditBundle`、
`RunMeteringStatement` 等 versioned envelopes 保持类名并要求 `schemaVersion=2`。不提供旧 core v1
Schema、JSON reader/upcaster 或历史 fixture。

`fairlead` 根 `__all__` 当前精确为 70 项。`fairlead_pydantic_ai` 是 0.12 新增命名空间，当前顶层
`__all__` 精确为 66 项；其 provisional contracts 使用显式 `V1` 类名并发布 21 个独立的
`fairlead_pydantic_ai/schemas/v1/` resources。这不是旧 core v1 reader，也不形成 backward-compatibility
承诺。API manifest 的 `schemaResources` 只逐项冻结 39 个 core v2 resources；integration Schema 由独立
exporter 与 distribution byte check 固定。

```python
from importlib import resources

schema_root = resources.files("fairlead").joinpath("schemas", "v2")
run_event_schema = schema_root.joinpath("run-event.schema.json").read_text(encoding="utf-8")
```

Schema 只表达跨语言形状；状态机、时间、usage、幂等和跨字段不变量仍以 Pydantic validator 与公共
reducer 为准。pre-1.0 maturity 描述当前 release 的设计置信度，不构成跨 minor compatibility promise。
精确清单见 [API maturity](https://github.com/gugia/fairlead/blob/v0.12.1/docs/contracts/api-maturity.md)。

## 中间件与 reference

core 不依赖 PostgreSQL、Redis、FastAPI、任务队列或前端框架。业务仍可组合：

```text
PostgreSQL  Journal / Result / Artifact metadata / Notification / Outbox
Redis       可选、可丢失的实时 hint
HTTP        提交与授权读取
SSE         非权威实时接收，断线后从 PostgreSQL 补读
```

`reference/postgres-host` 与 `reference/answer-service` 是源码模板/私有制品，不进入公共 wheel，也不自动
继承 core API 或生产资格。仓库测试不能证明目标环境 fsync、断电恢复、HA、RPO/RTO、容量、真实 IdP、
供应商 exactly-once 或业务语义质量。

## 开发与验证

```bash
cd /mnt/d/Projects/fairlead
export UV_LINK_MODE=copy
uv lock --check
uv sync --locked --all-groups
uv run --locked python scripts/verify_release_train.py --tag v0.12.1
uv run --locked ruff format --check .
uv run --locked ruff check .
uv run --locked mypy
uv run --locked python scripts/export_api_manifest.py --check
uv run --locked python scripts/export_contract_schemas.py --check
uv run --locked python scripts/export_pydantic_ai_schemas.py --check
uv run --locked pytest
uv build --no-sources
uv run --locked python scripts/verify_distribution.py
```

发布物门禁必须证明：单一 wheel 同时包含 `fairlead` 与 `fairlead_pydantic_ai`；纯 core 环境不安装或加载
Pydantic AI；integration extra 精确安装 2.36.0；Pydantic AI 1.x 被稳定拒绝；API manifest 的
`schemaResources` 精确只列 39 个 core v2 Schema；独立 integration exporter 和 distribution byte check
精确冻结 21 个新 integration v1 Schema；旧 core v1/fixture/reader 不再打包。

PostgreSQL/provider live qualification 需要显式隔离环境和预算；未设置条件产生的 skip 不能称为通过。
默认测试不读取 `.env.local`，不发真实模型请求。

## 发布边界

- 公共 PyPI：一个 `fairlead` wheel/sdist，包含两个顶层包；
- 私有/source template：`fairlead-reference-postgres-host`、`fairlead-reference-answer`；
- 不存在 `fairlead-pydantic-ai` 第二 distribution 或第二 workspace；
- tag、GitHub Release、quality run、构建候选和 PyPI OIDC 身份必须绑定同一 commit。

## License

[MIT](https://github.com/gugia/fairlead/blob/v0.12.1/LICENSE)
