Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .licenserc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,7 @@ header:
- '.gitattributes'
- '**/*.service.in'
- '**/*.jsonl'
# license-eye cannot determine the comment style of uv requirements files.
- 'e2e/bub/source-overrides.txt'

comment: on-failure
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ check: ## Run code quality tools.
@uv lock --locked
@echo "🚀 Linting code: Running prek"
@uv run prek run -a
@echo "🚀 Static type checking: Running ty"
@uv run ty check
@echo "🚀 Static type checking: Running ty for the Pydantic AI integration"
@uv run ty check integrations/pydantic-ai/src

.PHONY: test
test: ## Test the code with pytest
Expand Down
112 changes: 112 additions & 0 deletions docs/en/docs/how-to/configure-pydantic-ai.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
title: Configure Pydantic AI
description: Add durable Memory tools, automatic context preparation, and optional trajectory capture to Pydantic AI.
---

# Configure Pydantic AI

Use the independently released `powercontext-pydantic-ai` package when a Pydantic AI agent should share durable
Memory through a running PowerContext Server.

## Install the adapter

Start the Server, then install the adapter in the agent application:

```bash
uv add powercontext-pydantic-ai "pydantic-ai-slim[openai]"
```

The example below uses OpenAI. For another provider, install the matching `pydantic-ai-slim` provider extra and
change the model string.

Attach the capability to an Agent:

```python
from pydantic_ai import Agent
from powercontext_pydantic_ai import PowerContext

agent = Agent(
"openai:gpt-5.2",
capabilities=[PowerContext(scope_id="project:example")],
)
```

The capability adds `powercontext_search`, `powercontext_remember`, and `powercontext_context`. It also requests
`prepare_context` from the latest textual user prompt and prepends at most one untrusted evidence block per run. A new
run prepares context again even when it starts from the previous run's message history.

Use only the toolset when automatic preparation and capture are not wanted:

```python
from pydantic_ai import Agent
from powercontext_pydantic_ai import PowerContextToolset

agent = Agent("openai:gpt-5.2", toolsets=[PowerContextToolset()])
```

## Set environment configuration

```bash
export POWERCONTEXT_PYDANTIC_AI_BASE_URL=http://127.0.0.1:8000
export POWERCONTEXT_PYDANTIC_AI_TOKEN=opaque-server-token
export POWERCONTEXT_PYDANTIC_AI_SCOPE_ID=project:example
```

| Variable | Default | Validation and behavior |
| --- | --- | --- |
| `POWERCONTEXT_PYDANTIC_AI_BASE_URL` | `http://127.0.0.1:8000` | HTTP(S), without credentials, query, or fragment |
| `POWERCONTEXT_PYDANTIC_AI_TOKEN` | unset | Bare printable token stored as `SecretStr` |
| `POWERCONTEXT_PYDANTIC_AI_SCOPE_ID` | derived | Non-empty scope, deterministically bounded to 256 characters |
| `POWERCONTEXT_PYDANTIC_AI_TIMEOUT` | `10` | Positive seconds |
| `POWERCONTEXT_PYDANTIC_AI_MAX_BYTES` | `8000` | `512`–`32768` prepared-context bytes |
| `POWERCONTEXT_PYDANTIC_AI_CAPTURE_EVENTS` | `false` | Opt in to visible event capture |
| `POWERCONTEXT_PYDANTIC_AI_CAPTURE_CHECKPOINT_EVERY` | `5` | `1`–`100` successful events per flush |
| `POWERCONTEXT_PYDANTIC_AI_CAPTURE_MAX_BYTES` | `8192` | `512`–`32768` UTF-8 bytes per event |

Unlike the Codex and Claude Code plugin settings that accept a complete authorization value, this adapter accepts a
bare token. Do not include `Bearer ` or pass a complete `Authorization` header; the public Client adds the scheme.

Both `PowerContext` and `PowerContextToolset` accept a `PowerContextSettings` instance, a stable `id` (default
`powercontext`), and a fixed or callable `scope_id`:

```python
from pydantic_ai import RunContext
from powercontext_pydantic_ai import PowerContext, PowerContextSettings

settings = PowerContextSettings(timeout=5, max_bytes=4096)


def tenant_scope(ctx: RunContext[dict[str, str]]) -> str:
return f"tenant:{ctx.deps['tenant_id']}"


capability = PowerContext(settings=settings, scope_id=tenant_scope)
```

The callback runs once per Agent run. Scope precedence is constructor string or callback, environment `SCOPE_ID`,
normalized Git origin, then `local:<sha256-of-project-path>`. Explicit configuration avoids Git subprocesses.

## Decide whether to capture events

Capture is off by default. Set `POWERCONTEXT_PYDANTIC_AI_CAPTURE_EVENTS=true` only when sending the initial user text,
visible model text and tool calls, and completed tool arguments and results to the configured scope is acceptable.
Thinking/reasoning content is excluded. Events are redacted for credential-like keys and known environment/Codex
credentials, rendered within the configured byte limit, and stored under
`powercontext.pydantic-ai-capture-event/v1`.

Every successful Capture advances the run-local Source position. A checkpoint Flush runs after the configured number
of captures, and `after_run` flushes any remaining Source. Parallel tool results receive unique sequence numbers under
a run-local lock. Recall, Capture, and Flush fail open during Server failures; explicit tool failures become
`ModelRetry`. The first HTTP 401 or 403 logs one credential-free configuration warning.

Captured project content can remain sensitive after credential redaction. Protect the Server, scope, database, and
logs accordingly.

## Compare the MCP fallback

Connecting PowerContext MCP requires no adapter package, but it is a lower-capability option for Pydantic AI. MCP
provides explicit tools; it does not automatically call `prepare_context`, capture trajectory events, or Flush at
checkpoints and run completion.

This first adapter release supports ordinary Pydantic AI runs. Durable execution through Temporal, DBOS, Prefect, or
similar systems is not yet validated. Handoff, Candidate Review, Experience, and Skill operations are not included.
10 changes: 9 additions & 1 deletion docs/en/docs/reference/interfaces.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Interfaces
description: Choose between the Codex and Claude Code plugins, DeepSeek Harness plugin, Pi package, CLI, Python SDKs, HTTP, and MCP.
description: Choose between Agent integrations, the CLI, Python SDKs, HTTP, and MCP.
---

# Interfaces
Expand All @@ -10,6 +10,7 @@ All remote interfaces operate on the same Server and persistent Artifact storage
| Interface | Intended use | Install |
| --- | --- | --- |
| Codex plugin | Cross-session recall and explicit Memory maintenance in Codex | `powercontext setup codex` |
| Pydantic AI adapter | Memory tools, automatic context preparation, and optional trajectory capture | `powercontext-pydantic-ai` |
| DeepSeek Harness plugin | Cross-session recall and explicit Memory maintenance in DeepSeek Harness | `powercontext setup dsh` |
| LangGraph adapter | Memory tools and bounded recall inside a LangGraph graph | `powercontext-langgraph` |
| Pi package | Cross-session recall, native Memory/Handoff tools, and skills in Pi | `powercontext setup pi` |
Expand Down Expand Up @@ -71,6 +72,13 @@ The project-context skill tells DeepSeek Harness when to search, remember, revis
step the plugin recalls relevant entries and captures user input as Source evidence. Named `pc_*` tools perform explicit
HTTP operations. The plugin never starts or embeds the Server.

## Pydantic AI adapter

The independent `powercontext-pydantic-ai` distribution contributes three Memory tools through the public Python
Client and can automatically prepend bounded `PreparedContext`. Optional capture stores redacted, bounded visible
model and completed tool events, performs checkpoint Flush, and flushes remaining Sources after the run. MCP needs no
adapter package but does not provide automatic context preparation, capture, or Flush. See
[Configure Pydantic AI](../how-to/configure-pydantic-ai.md).
## LangGraph adapter

`powercontext-langgraph` connects a LangGraph graph to a running Server through the public Python Client. It supplies
Expand Down
107 changes: 107 additions & 0 deletions docs/zh/docs/how-to/configure-pydantic-ai.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
title: 配置 Pydantic AI
description: 为 Pydantic AI 增加持久化 Memory 工具、自动 Context 准备和可选轨迹采集。
---

# 配置 Pydantic AI

当 Pydantic AI Agent 需要通过运行中的 PowerContext Server 共享持久化 Memory 时,安装独立发行的
`powercontext-pydantic-ai` 包。

## 安装适配器

先启动 Server,再在 Agent 应用中安装:

```bash
uv add powercontext-pydantic-ai "pydantic-ai-slim[openai]"
```

下面的示例使用 OpenAI。使用其他 Provider 时,请安装匹配的 `pydantic-ai-slim` Provider extra,并修改模型字符串。

把 Capability 加到 Agent:

```python
from pydantic_ai import Agent
from powercontext_pydantic_ai import PowerContext

agent = Agent(
"openai:gpt-5.2",
capabilities=[PowerContext(scope_id="project:example")],
)
```

该 Capability 提供 `powercontext_search`、`powercontext_remember` 和 `powercontext_context`。它还会从最新文本
User Prompt 请求 `prepare_context`,并在一个 run 内最多前置一次不可信证据块。即使新 run 复用旧 message
history,也会重新准备 Context。

如果只需要工具,不需要自动准备与采集,可以只挂载 Toolset:

```python
from pydantic_ai import Agent
from powercontext_pydantic_ai import PowerContextToolset

agent = Agent("openai:gpt-5.2", toolsets=[PowerContextToolset()])
```

## 设置环境变量

```bash
export POWERCONTEXT_PYDANTIC_AI_BASE_URL=http://127.0.0.1:8000
export POWERCONTEXT_PYDANTIC_AI_TOKEN=opaque-server-token
export POWERCONTEXT_PYDANTIC_AI_SCOPE_ID=project:example
```

| 变量 | 默认值 | 校验与行为 |
| --- | --- | --- |
| `POWERCONTEXT_PYDANTIC_AI_BASE_URL` | `http://127.0.0.1:8000` | HTTP(S),不能含凭证、query 或 fragment |
| `POWERCONTEXT_PYDANTIC_AI_TOKEN` | 未设置 | 以 `SecretStr` 保存的裸可打印 Token |
| `POWERCONTEXT_PYDANTIC_AI_SCOPE_ID` | 自动推导 | 非空,并确定性收敛到最多 256 个字符 |
| `POWERCONTEXT_PYDANTIC_AI_TIMEOUT` | `10` | 正秒数 |
| `POWERCONTEXT_PYDANTIC_AI_MAX_BYTES` | `8000` | `512`–`32768` Context 字节 |
| `POWERCONTEXT_PYDANTIC_AI_CAPTURE_EVENTS` | `false` | 显式同意采集可见事件 |
| `POWERCONTEXT_PYDANTIC_AI_CAPTURE_CHECKPOINT_EVERY` | `5` | 每 `1`–`100` 个成功事件 Flush |
| `POWERCONTEXT_PYDANTIC_AI_CAPTURE_MAX_BYTES` | `8192` | 每个事件 `512`–`32768` UTF-8 字节 |

Codex 与 Claude Code 插件的相关设置接收完整 authorization 值,而本适配器只接收裸 Token。不要带
`Bearer `,也不要传完整 `Authorization` Header;公共 Client 会补上 scheme。

`PowerContext` 与 `PowerContextToolset` 都接受 `PowerContextSettings`、稳定的 `id`(默认 `powercontext`),
以及固定或回调形式的 `scope_id`:

```python
from pydantic_ai import RunContext
from powercontext_pydantic_ai import PowerContext, PowerContextSettings

settings = PowerContextSettings(timeout=5, max_bytes=4096)


def tenant_scope(ctx: RunContext[dict[str, str]]) -> str:
return f"tenant:{ctx.deps['tenant_id']}"


capability = PowerContext(settings=settings, scope_id=tenant_scope)
```

回调在每个 Agent run 内只执行一次。Scope 优先级是:构造器字符串或回调、环境变量 `SCOPE_ID`、规范化 Git
origin,最后是 `local:<project-path-sha256>`。显式配置时不会调用 Git。

## 决定是否采集事件

Capture 默认关闭。只有在允许把初始用户文本、可见模型文本和工具调用、已完成的工具参数与结果发送到指定 scope
时,才设置 `POWERCONTEXT_PYDANTIC_AI_CAPTURE_EVENTS=true`。Thinking/reasoning 内容不会采集。事件会清洗敏感键、
已知环境凭证和 Codex 凭证,按配置的字节上限渲染,并使用
`powercontext.pydantic-ai-capture-event/v1` schema。

每次成功 Capture 都会推进 run-local Source position。达到配置数量时执行 checkpoint Flush,`after_run` 会 Flush
剩余 Source;并发工具结果在 run-local lock 下获得唯一序号。Recall、Capture 和 Flush 遇到 Server 故障时 fail-open;
显式工具失败则转换为 `ModelRetry`。HTTP 401 或 403 首次出现时只记录一条不含凭证的配置告警。

凭证清洗不能保证普通项目内容不敏感,请同时保护 Server、scope、数据库和日志。

## 与 MCP 备选方案比较

连接 PowerContext MCP 不需要额外适配器包,但对 Pydantic AI 来说能力较低。MCP 提供显式工具,不会自动调用
`prepare_context`,也不会采集轨迹或在 checkpoint/run 结束时 Flush。

首版只支持普通 Pydantic AI run;Temporal、DBOS、Prefect 等 durable execution 尚未验证。Handoff、Candidate
Review、Experience 与 Skill operation 不在本适配器范围内。
9 changes: 8 additions & 1 deletion docs/zh/docs/reference/interfaces.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 接口
description: 在 Codex 和 Claude Code 插件、DeepSeek Harness 插件、Pi package、CLI、Python SDK、HTTP 和 MCP 之间选择。
description: 在 Agent 集成、CLI、Python SDK、HTTP 和 MCP 之间选择。
---

# 接口
Expand All @@ -10,6 +10,7 @@ description: 在 Codex 和 Claude Code 插件、DeepSeek Harness 插件、Pi pac
| 接口 | 适用场景 | 安装 |
| --- | --- | --- |
| Codex 插件 | 在 Codex 中跨会话恢复和显式维护 Memory | `powercontext setup codex` |
| Pydantic AI 适配器 | Memory 工具、自动 Context 准备和可选轨迹采集 | `powercontext-pydantic-ai` |
| DeepSeek Harness 插件 | 在 DeepSeek Harness 中跨会话恢复和显式维护 Memory | `powercontext setup dsh` |
| LangGraph 适配器 | 在 LangGraph 图中提供 Memory 工具和有界召回 | `powercontext-langgraph` |
| Pi package | 在 Pi 中跨会话恢复、使用原生 Memory/Handoff 工具和 skill | `powercontext setup pi` |
Expand Down Expand Up @@ -63,6 +64,12 @@ Handoff Report 的 JSON Workstream projection 同时返回 `handoff_revision_cou
project-context skill 指导 DeepSeek Harness 何时检索、记忆、修订或停用 Memory。每轮模型开口前,插件会恢复相关
条目,并把用户输入采集为 Source 证据;具名 `pc_*` 工具执行显式 HTTP 操作。插件不会启动或内嵌 Server。

## Pydantic AI 适配器

独立发行的 `powercontext-pydantic-ai` 通过公共 Python Client 提供三个 Memory 工具,并可自动前置有界
`PreparedContext`。可选 Capture 会保存经过清洗和限长的可见模型事件与已完成工具事件,执行 checkpoint Flush,并在
run 结束后 Flush 剩余 Source。MCP 不需要适配器包,但不提供自动 Context 准备、Capture 或 Flush。参见
[配置 Pydantic AI](../how-to/configure-pydantic-ai.md)。
## LangGraph 适配器

`powercontext-langgraph` 通过公开的 Python Client 把 LangGraph 图连接到运行中的 Server,提供三个组件:
Expand Down
18 changes: 18 additions & 0 deletions e2e/bub/source-overrides.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) 2026 OceanBase.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# The acceptance harness mounts the current unreleased checkout into the trial
# container. Force that source distribution without weakening the integration's
# published minimum PowerContext version.
powercontext[client] @ file:///opt/powercontext/source
3 changes: 2 additions & 1 deletion e2e/bub/src/powercontext_e2e/harbor_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
REMOTE_CODEX_AUTH = "/run/powercontext/codex-auth.json"
REMOTE_CODEX_HOME = "/installed-agent/codex"
REMOTE_SOURCE = "/opt/powercontext/source"
REMOTE_SOURCE_OVERRIDE = f"{REMOTE_SOURCE}/e2e/bub/source-overrides.txt"
REMOTE_TOOL_DIR = "/installed-agent/tools"
BUB_VERSION = version("bub")
POWERCONTEXT_VERSION = version("powercontext")
Expand Down Expand Up @@ -129,7 +130,7 @@ def _install_bub_command() -> str:
"fi; "
f"SETUPTOOLS_SCM_PRETEND_VERSION={shlex.quote(POWERCONTEXT_VERSION)} {_tool_environment()} "
f"{uv} tool install --force "
f"--with {REMOTE_SOURCE} --with {REMOTE_SOURCE}/integrations/bub "
f"--overrides {REMOTE_SOURCE_OVERRIDE} --with {REMOTE_SOURCE}/integrations/bub "
f"{shlex.quote(f'bub=={BUB_VERSION}')}"
)

Expand Down
15 changes: 14 additions & 1 deletion e2e/bub/tests/test_harbor_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,24 @@

import shlex
from importlib.metadata import version
from pathlib import Path

from powercontext_e2e.harbor_agent import _install_bub_command
from powercontext_e2e.harbor_agent import REMOTE_SOURCE_OVERRIDE, _install_bub_command

_SOURCE_OVERRIDE = Path(__file__).resolve().parents[1] / "source-overrides.txt"


def test_install_bub_command_provides_powercontext_version() -> None:
version_assignment = f"SETUPTOOLS_SCM_PRETEND_VERSION={shlex.quote(version('powercontext'))}"

assert version_assignment in _install_bub_command().split()


def test_install_bub_command_overrides_release_floor_for_mounted_source() -> None:
command = shlex.split(_install_bub_command())
override_index = command.index("--overrides")

assert command[override_index + 1] == REMOTE_SOURCE_OVERRIDE
assert _SOURCE_OVERRIDE.read_text(encoding="utf-8").splitlines()[-1] == (
"powercontext[client] @ file:///opt/powercontext/source"
)
2 changes: 1 addition & 1 deletion e2e/bub/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion integrations/bub/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ description = "Bub integration for PowerContext durable memory."
requires-python = ">=3.12,<4.0"
dependencies = [
"bub>=0.4.0,<0.5.0",
"powercontext[client]>=0.0.1",
"powercontext[client]>=0.0.3",
"pydantic-settings>=2.7,<3",
]

Expand Down
Loading
Loading