feat(integrations): support pydantic-ai integrate - #1295
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a first-class Pydantic AI integration for PowerContext as an independently distributable package under integrations/, aligning PowerContext’s memory/tooling with Pydantic AI’s run lifecycle (context prep, optional capture, flushing) via the public Python client.
Changes:
- Introduces
powercontext-pydantic-aiwith public APIs (PowerContext,PowerContextToolset,PowerContextSettings), memory tools, deterministic scope resolution, and per-run client lifecycle. - Adds optional bounded, redacted trajectory capture + checkpoint/final flushing, and factors shared capture rendering/redaction into
powercontext.client.capture(reused by Bub). - Adds adapter unit tests, an e2e chain test, and updates docs/navigation and repo test/type-check import paths for the new integration.
Reviewed changes
Copilot reviewed 23 out of 24 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| zensical.toml | Adds Pydantic AI docs pages into EN/ZH navigation. |
| pyproject.toml | Updates type-check/test import paths to include the integration source during repo tests. |
| src/powercontext/client/capture.py | New shared bounded/redacted JSON rendering utilities for capture events. |
| integrations/pydantic-ai/pyproject.toml | Declares the independently distributable powercontext-pydantic-ai package metadata/deps. |
| integrations/pydantic-ai/README.md | Provides installation, configuration, and behavior documentation for the adapter package. |
| integrations/pydantic-ai/src/powercontext_pydantic_ai/init.py | Exposes the adapter’s public API surface. |
| integrations/pydantic-ai/src/powercontext_pydantic_ai/settings.py | Adds validated settings loading via pydantic-settings env prefix. |
| integrations/pydantic-ai/src/powercontext_pydantic_ai/scope.py | Implements deterministic scope resolution (constructor/env/git/local hash). |
| integrations/pydantic-ai/src/powercontext_pydantic_ai/toolset.py | Implements the toolset (search/remember/context) with per-run client management and ModelRetry mapping. |
| integrations/pydantic-ai/src/powercontext_pydantic_ai/capability.py | Implements automatic context prep, optional capture, and flush hooks in the Pydantic AI capability lifecycle. |
| integrations/bub/src/powercontext_bub/plugin.py | Switches Bub capture rendering to the shared capture helper. |
| integrations/bub/pyproject.toml | Bumps Bub integration dependency to powercontext[client]>=0.0.2. |
| e2e/bub/uv.lock | Updates lockfile to reflect the powercontext[client]>=0.0.2 requirement. |
| docs/en/docs/reference/interfaces.md | Documents the new Pydantic AI adapter as a supported interface. |
| docs/zh/docs/reference/interfaces.md | Documents the new Pydantic AI adapter as a supported interface (ZH). |
| docs/en/docs/how-to/configure-pydantic-ai.md | Adds end-user setup/configuration documentation (EN). |
| docs/zh/docs/how-to/configure-pydantic-ai.md | Adds end-user setup/configuration documentation (ZH). |
| tests/pydantic_ai_adapter/init.py | Adds a dedicated test package for the adapter tests. |
| tests/pydantic_ai_adapter/fakes.py | Adds a recording PowerContext client test double for adapter-boundary assertions. |
| tests/pydantic_ai_adapter/test_toolset.py | Validates tool schemas/instructions/mapping, retry conversion, and per-run client lifecycle. |
| tests/pydantic_ai_adapter/test_settings_scope.py | Validates settings/env behavior and scope derivation precedence/bounding. |
| tests/pydantic_ai_adapter/test_capability.py | Validates per-run context injection rules and fail-open recall behavior. |
| tests/pydantic_ai_adapter/test_capture.py | Validates capture opt-in, bounding/redaction, checkpoint flushing, and fail-open capture/flush behavior. |
| tests/e2e/test_pydantic_ai_chain.py | Adds an end-to-end chain test using a real server lifecycle + SQLite to validate capture→flush→recall→search. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
@PsiACE This PR is ready for review, plz review it when you are free, thx. |
| if state.captured_position <= state.flushed_position: | ||
| return | ||
| try: | ||
| response = await self._toolset._require_client().flush_memory(FlushMemoryRequest(scope_id=state.scope_id)) |
There was a problem hiding this comment.
[P1] checkpoint/final flush 不能保证追到本次捕获位置
这里每次只调用一次 flush_memory,但 Server 每次最多处理 source_window_limit 个 Source;当同一 scope 已有 backlog 时,返回的 current_cursor 仍可能小于 state.captured_position。使用真实 SQLite Server、source_window_limit=1 和两条 backlog 的探针中,本次 tool result 位于 position 5,checkpoint 与 final flush 后 cursor 只到 1、2,下一次 model request 看不到该结果;继续手工 flush 到 5 后才可召回。这会破坏 checkpoint 的 read-your-write 语义。建议在 deadline/max-calls/no-progress 约束下循环,直到 cursor 到达本次捕获位置,并补一个返回 partial cursor 的回归测试。
|
|
||
| if isinstance(value, Mapping): | ||
| return { | ||
| str(key): REDACTED if is_sensitive_key(str(key)) else sanitize_capture_value(item) |
There was a problem hiding this comment.
[P1] 当前 sanitizer 会原样持久化常见凭据形态
这里的 key 归一化无法识别 camelCase apiKey(会变成 apikey,但规则只含 api_key);同时非 Mapping 的字符串会原样返回,而 locked Pydantic AI 2.29 的 ToolCallPart.args 是 str | dict | None,OpenAI adapter 会直接传入 JSON 字符串。探针确认 {"apiKey":"..."} 和字符串形式的 {"api_key":"..."} 都保留了 synthetic secret。capture 会持久化 tool arguments/results,这会绕过文档承诺的 credential redaction。建议覆盖 camelCase/compact aliases,并对结构化 JSON 参数使用 args_as_dict() 或安全解析后递归脱敏,补两种形态的回归测试。
| run_id=ctx.run_id, | ||
| conversation_id=ctx.conversation_id, | ||
| ) | ||
| return replace(request_context, messages=[context_request, *request_context.messages]) |
There was a problem hiding this comment.
[P1] 新 run 应替换旧的 PowerContext context
这里直接把新 context 前置到完整 message_history,旧 run 注入的 CONTEXT_MARKER 消息不会被移除。连续三次 agent.run(..., message_history=previous.all_messages()) 的公开路径探针得到 marker 数 [1, 2, 3];第三轮同时携带 context-1、context-2、context-3,既让陈旧 system context 继续影响模型,也会按每轮最多 8KB 线性膨胀历史。建议在插入当前 run context 前过滤或替换旧的 PowerContext-marked request,保证复用历史时始终只有一个当前 context,并增加多 run 回归测试。
Which issue or RFC does this PR close?
Closes #1269 .
Rationale for this change
Pydantic AI users currently lack a native PowerContext integration that follows Pydantic AI’s toolset and capability lifecycles.
This PR adds an independent adapter that provides Memory tools, automatic context preparation, optional event capture, and checkpoint flushing through the public PowerContext Python Client.
What changes are included in this PR?
powercontext-pydantic-aipackage.PowerContextSettingsPowerContextToolsetPowerContextPowerContextClientlifecycle management and the following tools:powercontext_searchpowercontext_rememberpowercontext_contextPOWERCONTEXT_PYDANTIC_AI_SCOPE_IDModelRetryerrors.powercontext.client.capture, and reuse it in the Bub integration.FunctionModel, the real server lifecycle, and SQLite.This PR does not modify the server API, OpenAPI schema, or MCP allow-list.
Are there any user-facing changes?
Yes. Users can install the new package and attach PowerContext directly to a Pydantic AI agent.
The integration introduces new
POWERCONTEXT_PYDANTIC_AI_*configuration variables. The token setting expects a raw token; users should not include theBearerprefix.Capture is opt-in and disabled by default because enabling it may persist prompts, visible model output, tool calls, and tool results. Sensitive values are redacted before capture, but users should still review the associated data-retention risk.
There are no breaking changes to existing public APIs or persisted formats, and no migration is required. Durable execution frameworks such as Temporal, DBOS, and Prefect have not been validated in this initial release.
How was this change tested?
The following validation was completed:
25 passedmake test:631 passed, 12 skipped1 passedmake checkmake docs-testuv build --project integrations/pydantic-aitoxacross Python 3.11, 3.12, 3.13, and 3.14integrations/pydantic-ai/srcThe end-to-end test verifies the complete flow:
An initial Python 3.12 tox run encountered an existing readiness-test timeout; both the isolated test and the complete Python 3.12 environment passed on rerun.
AI usage statement