acpkit 0.5.0__tar.gz → 0.7.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.
- acpkit-0.7.0/.agents/skills/acpkit-sdk/SKILL.md +830 -0
- acpkit-0.7.0/.agents/skills/acpkit-sdk/resources/intro.md +171 -0
- acpkit-0.7.0/.github/workflows/codecov.yml +30 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.github/workflows/test.yml +2 -2
- {acpkit-0.5.0 → acpkit-0.7.0}/.gitignore +8 -2
- {acpkit-0.5.0 → acpkit-0.7.0}/.pre-commit-config.yaml +12 -0
- acpkit-0.7.0/CONTRIBUTING.md +117 -0
- acpkit-0.7.0/COVERAGE +2 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/Makefile +1 -1
- {acpkit-0.5.0 → acpkit-0.7.0}/PKG-INFO +41 -6
- {acpkit-0.5.0 → acpkit-0.7.0}/README.md +40 -5
- acpkit-0.7.0/VERSION +1 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/about/index.md +8 -1
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/api/acpkit.md +8 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/api/pydantic_acp.md +34 -0
- acpkit-0.7.0/docs/bridges.md +346 -0
- acpkit-0.7.0/docs/compatibility-matrix-template.md +246 -0
- acpkit-0.7.0/docs/examples/index.md +43 -0
- acpkit-0.7.0/docs/host-backends.md +302 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/index.md +9 -4
- acpkit-0.7.0/docs/integration-audit.md +136 -0
- acpkit-0.7.0/docs/integration-readiness.md +70 -0
- acpkit-0.7.0/docs/integration-testing.md +277 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/llms-full.txt +750 -17
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/llms.txt +3 -0
- acpkit-0.7.0/docs/projection-cookbook.md +222 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/pydantic-acp/adapter-config.md +8 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/pydantic-acp/plans-thinking-approvals.md +14 -0
- acpkit-0.7.0/docs/pydantic-acp/prompt-resources.md +214 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/pydantic-acp/session-state.md +17 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/pydantic-acp.md +27 -3
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/testing.md +19 -1
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/strong_agent.py +93 -17
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/strong_agent_v2.py +158 -17
- {acpkit-0.5.0 → acpkit-0.7.0}/mkdocs.yml +6 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/README.md +16 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/VERSION +1 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/pyproject.toml +4 -1
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/__init__.py +56 -1
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/_projection_risk.py +48 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/_projection_text.py +118 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/_version.py +5 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/bridges/__init__.py +2 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/bridges/_hook_capability.py +497 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/bridges/history_processor.py +11 -8
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/bridges/hooks.py +66 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/bridges/mcp.py +12 -1
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/builders/agent.py +6 -10
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/config.py +7 -1
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/hook_projection.py +3 -3
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/host/__init__.py +12 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/host/_policy_commands.py +82 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/host/_policy_paths.py +28 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/host/context.py +69 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/host/filesystem.py +15 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/host/policy.py +409 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/host/terminal.py +22 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/projection.py +156 -91
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/projection_helpers.py +24 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/providers.py +16 -2
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_adapter_prompt.py +273 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_native_plan_runtime.py +335 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_prompt_execution.py +384 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_prompt_model_runtime.py +157 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_prompt_runtime.py +349 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_session_lifecycle.py +137 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_session_model_runtime.py +187 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_session_runtime.py +609 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_session_surface_runtime.py +459 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/adapter.py +41 -173
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/hook_introspection.py +90 -4
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/prompts.py +107 -4
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/slash_commands.py +3 -1
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/session/store.py +248 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/testing/__init__.py +11 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/testing/fakes.py +246 -0
- acpkit-0.7.0/packages/adapters/pydantic-acp/src/pydantic_acp/testing/harness.py +162 -0
- acpkit-0.7.0/packages/helpers/codex-auth-helper/VERSION +1 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/pyproject.toml +4 -1
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/src/codex_auth_helper/__init__.py +2 -0
- acpkit-0.7.0/packages/helpers/codex-auth-helper/src/codex_auth_helper/_version.py +5 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/pyproject.toml +4 -1
- acpkit-0.7.0/scripts/check_pypi_versions.py +159 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/scripts/generate_llms_docs.py +6 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/src/acpkit/__init__.py +6 -2
- acpkit-0.7.0/src/acpkit/_compatibility_schema.py +111 -0
- acpkit-0.7.0/src/acpkit/_version.py +5 -0
- acpkit-0.7.0/src/acpkit/compatibility.py +15 -0
- acpkit-0.7.0/tests/conftest.py +30 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/support.py +2 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_adapter_helpers.py +110 -40
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_bridge_mcp.py +40 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_bridge_thinking.py +9 -1
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_hook_introspection.py +39 -0
- acpkit-0.7.0/tests/pydantic/test_host_policy.py +247 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_low_level_helpers.py +273 -22
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_models.py +8 -2
- acpkit-0.7.0/tests/pydantic/test_projection_helpers.py +126 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_runtime.py +182 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_slash_commands.py +41 -6
- acpkit-0.7.0/tests/pydantic/test_testing_fakes.py +165 -0
- acpkit-0.7.0/tests/pydantic/test_testing_harness.py +118 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/test_acpkit_cli.py +34 -0
- acpkit-0.7.0/tests/test_compatibility_manifest.py +103 -0
- acpkit-0.5.0/.agents/skills/acpkit-sdk/SKILL.md +0 -57
- acpkit-0.5.0/.agents/skills/acpkit-sdk/resources/intro.md +0 -79
- acpkit-0.5.0/CONTRIBUTING.md +0 -41
- acpkit-0.5.0/COVERAGE +0 -2
- acpkit-0.5.0/SKILL.md +0 -452
- acpkit-0.5.0/VERSION +0 -1
- acpkit-0.5.0/docs/bridges.md +0 -186
- acpkit-0.5.0/docs/examples/index.md +0 -43
- acpkit-0.5.0/docs/host-backends.md +0 -109
- acpkit-0.5.0/packages/adapters/pydantic-acp/VERSION +0 -1
- acpkit-0.5.0/packages/adapters/pydantic-acp/src/pydantic_acp/bridges/hooks.py +0 -507
- acpkit-0.5.0/packages/adapters/pydantic-acp/src/pydantic_acp/host/context.py +0 -40
- acpkit-0.5.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_prompt_runtime.py +0 -803
- acpkit-0.5.0/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_session_runtime.py +0 -1015
- acpkit-0.5.0/packages/adapters/pydantic-acp/src/pydantic_acp/session/store.py +0 -165
- acpkit-0.5.0/packages/helpers/codex-auth-helper/VERSION +0 -1
- acpkit-0.5.0/tests/conftest.py +0 -18
- {acpkit-0.5.0 → acpkit-0.7.0}/.agents/skills/acpkit-sdk/agents/openai.yaml +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.agents/skills/acpkit-sdk/scripts/list_examples.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.agents/skills/acpkit-sdk/scripts/list_public_exports.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.cursorrules +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.editorconfig +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.github/dependabot.yml +0 -0
- /acpkit-0.5.0/.github/workflows/monorepo-ci.yml → /acpkit-0.7.0/.github/workflows/ci.yml +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.github/workflows/docs.yml +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.github/workflows/publish.yml +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/.python-version +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/CODE_OF_CONDUCT.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/LICENSE +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/SECURITY.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/context7.json +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/.partials/index-header.html +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/api/codex_auth_helper.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/cli.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/examples/factory.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/examples/minimal.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/examples/providers.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/examples/workspace-agent.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/getting-started/installation.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/getting-started/quickstart.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/helpers.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/providers.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/pydantic-acp/runtime-controls.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/docs/stylesheets/tweaks.css +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/__init__.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/.gitignore +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/README.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/__init__.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/approvals.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/bridges.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/factory_agent.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/hook_projection.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/host_context.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/providers.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/examples/pydantic/static_agent.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/_slash_commands.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/agent_source.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/agent_types.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/approvals.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/awaitables.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/bridges/base.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/bridges/prepare_tools.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/bridges/thinking.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/builders/__init__.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/models.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/py.typed +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/__init__.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/_agent_state.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/bridge_manager.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/server.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/runtime/session_surface.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/serialization.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/session/__init__.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/adapters/pydantic-acp/src/pydantic_acp/session/state.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/.gitignore +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/LICENSE +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/README.md +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/src/codex_auth_helper/auth/__init__.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/src/codex_auth_helper/auth/config.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/src/codex_auth_helper/auth/manager.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/src/codex_auth_helper/auth/state.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/src/codex_auth_helper/auth/store.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/src/codex_auth_helper/client.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/src/codex_auth_helper/factory.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/src/codex_auth_helper/model.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/packages/helpers/codex-auth-helper/src/codex_auth_helper/py.typed +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/pyrightconfig.json +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/scripts/demo_mcp_server.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/scripts/mock_hook_audit.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/scripts/mock_hook_snapshot.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/scripts/run_if_major_change.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/scripts/save_coverage_summary.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/src/acpkit/__main__.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/src/acpkit/adapters.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/src/acpkit/cli.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/src/acpkit/py.typed +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/src/acpkit/runtime.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/__init__.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/codex_auth_helper/__init__.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/codex_auth_helper/support.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/codex_auth_helper/test_factory.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/__init__.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_approvals.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_bridge_builder.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_bridge_hooks.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_bridge_prepare_tools.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_host.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_projection.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/pydantic/test_sources.py +0 -0
- {acpkit-0.5.0 → acpkit-0.7.0}/tests/test_native_pydantic_agent.py +0 -0
|
@@ -0,0 +1,830 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: acpkit-sdk
|
|
3
|
+
description: Use for ACP Kit SDK tasks that turn an existing agent surface into a truthful ACP server through acpkit, pydantic-acp, the published docs, and the maintained examples.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ACP Kit SDK
|
|
7
|
+
|
|
8
|
+
ACP Kit is the adapter toolkit and monorepo for turning an existing agent surface into a truthful ACP server boundary.
|
|
9
|
+
|
|
10
|
+
Today the stable production focus is `pydantic-acp`: exposing `pydantic_ai.Agent` through ACP
|
|
11
|
+
while keeping models, modes, plans, approvals, MCP metadata, host tools, and session state
|
|
12
|
+
aligned with what the underlying runtime can actually support.
|
|
13
|
+
|
|
14
|
+
Additional adapters such as `langchain-acp` and `dspy-acp` are planned after `pydantic-acp`
|
|
15
|
+
reaches 1.0 stability.
|
|
16
|
+
|
|
17
|
+
This skill file is the longform, high-context entrypoint for the packaged `acpkit-sdk` skill and
|
|
18
|
+
should be treated as the primary skill surface when the skill is selected.
|
|
19
|
+
|
|
20
|
+
When you need the docs map or the full docs corpus in one place, read [llms.txt](https://vcoderun.github.io/acpkit/llms.txt) or [llms-full.txt](https://vcoderun.github.io/acpkit/llms-full.txt).
|
|
21
|
+
|
|
22
|
+
## What ACP Kit Ships
|
|
23
|
+
|
|
24
|
+
ACP Kit currently has three main Python packages:
|
|
25
|
+
|
|
26
|
+
| Package | Role | Typical use |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| `acpkit` | root CLI and target resolver | `acpkit run ...`, `acpkit launch ...`, target loading |
|
|
29
|
+
| `pydantic-acp` | ACP adapter for `pydantic_ai.Agent` | expose an existing agent through ACP without rewriting it |
|
|
30
|
+
| `codex-auth-helper` | Codex-backed Pydantic AI helper | build Codex-backed Responses models from a local Codex login |
|
|
31
|
+
|
|
32
|
+
The core contract across the repo is:
|
|
33
|
+
|
|
34
|
+
> expose ACP state only when the underlying runtime can actually honor it.
|
|
35
|
+
|
|
36
|
+
That rule affects model selection, mode switching, slash commands, native plan state, approval
|
|
37
|
+
flow, MCP metadata, hook rendering, cancellation, and host-backed tooling.
|
|
38
|
+
|
|
39
|
+
## Use The Right Construction Seam
|
|
40
|
+
|
|
41
|
+
Pick the narrowest seam that matches the job:
|
|
42
|
+
|
|
43
|
+
| Seam | Use it when |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `run_acp(agent=...)` | you want the smallest direct path from `pydantic_ai.Agent` to a running ACP server |
|
|
46
|
+
| `create_acp_agent(...)` | you need the ACP-compatible agent object before running it |
|
|
47
|
+
| `agent_factory=` | the current session should influence agent construction, but a full custom source is unnecessary |
|
|
48
|
+
| `agent_source=` | you need full control over the agent build path, host binding, and session-specific dependencies |
|
|
49
|
+
| built-in `AdapterConfig` fields | the adapter can own the relevant runtime state cleanly |
|
|
50
|
+
| providers | the host or product layer should remain the source of truth |
|
|
51
|
+
| bridges | the runtime needs ACP-visible capabilities without hard-coding them into the adapter core |
|
|
52
|
+
|
|
53
|
+
## CLI And Target Resolution
|
|
54
|
+
|
|
55
|
+
The root `acpkit` package resolves Python targets and dispatches them to the matching adapter.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
acpkit run my_agent
|
|
59
|
+
acpkit run my_agent:agent
|
|
60
|
+
acpkit run app.agents.demo:agent -p ./examples
|
|
61
|
+
acpkit launch my_agent:agent -p ./examples
|
|
62
|
+
acpkit launch --command "python3.11 strong_agent.py"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Target resolution behavior:
|
|
66
|
+
|
|
67
|
+
1. add the current working directory to `sys.path`
|
|
68
|
+
2. add any `-p/--path` roots
|
|
69
|
+
3. import the requested module
|
|
70
|
+
4. if `module:attribute` was given, resolve the attribute path
|
|
71
|
+
5. if only `module` was given, select the last defined `pydantic_ai.Agent` in that module
|
|
72
|
+
|
|
73
|
+
Current built-in auto-dispatch support is centered on `pydantic_ai.Agent`.
|
|
74
|
+
|
|
75
|
+
## Smallest Adapter Path: `run_acp(...)`
|
|
76
|
+
|
|
77
|
+
Use `run_acp(...)` when one existing agent instance is enough.
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from pydantic_ai import Agent
|
|
81
|
+
from pydantic_acp import run_acp
|
|
82
|
+
|
|
83
|
+
agent = Agent(
|
|
84
|
+
'openai:gpt-5',
|
|
85
|
+
name='weather-agent',
|
|
86
|
+
instructions='Answer briefly and ask for clarification when location is missing.',
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@agent.tool_plain
|
|
91
|
+
def lookup_weather(city: str) -> str:
|
|
92
|
+
"""Return a canned weather response for demos."""
|
|
93
|
+
|
|
94
|
+
return f'Weather in {city}: sunny'
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
run_acp(agent=agent)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This is the narrowest path from an existing agent surface to a live ACP server.
|
|
101
|
+
|
|
102
|
+
## ACP Agent Without Running: `create_acp_agent(...)`
|
|
103
|
+
|
|
104
|
+
Use `create_acp_agent(...)` when you need the ACP-compatible agent object first.
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from acp import run_agent
|
|
108
|
+
from pydantic_ai import Agent
|
|
109
|
+
from pydantic_acp import AdapterConfig, MemorySessionStore, create_acp_agent
|
|
110
|
+
|
|
111
|
+
agent = Agent('openai:gpt-5', name='composable-agent')
|
|
112
|
+
|
|
113
|
+
acp_agent = create_acp_agent(
|
|
114
|
+
agent=agent,
|
|
115
|
+
config=AdapterConfig(
|
|
116
|
+
agent_name='my-service',
|
|
117
|
+
agent_title='My Service Agent',
|
|
118
|
+
session_store=MemorySessionStore(),
|
|
119
|
+
),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# later:
|
|
123
|
+
# await run_agent(acp_agent)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Use this seam when ACP is only one part of a larger async service boundary.
|
|
127
|
+
|
|
128
|
+
## `AdapterConfig` Is The Main Runtime Surface
|
|
129
|
+
|
|
130
|
+
`AdapterConfig` is where the adapter’s built-in ownership lives:
|
|
131
|
+
|
|
132
|
+
- session storage
|
|
133
|
+
- model selection
|
|
134
|
+
- approval bridging
|
|
135
|
+
- capability bridges
|
|
136
|
+
- plan persistence callbacks
|
|
137
|
+
- hook projection and runtime shaping
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from pathlib import Path
|
|
141
|
+
|
|
142
|
+
from pydantic_ai import Agent
|
|
143
|
+
from pydantic_acp import (
|
|
144
|
+
AdapterConfig,
|
|
145
|
+
AdapterModel,
|
|
146
|
+
FileSessionStore,
|
|
147
|
+
NativeApprovalBridge,
|
|
148
|
+
ThinkingBridge,
|
|
149
|
+
run_acp,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
agent = Agent('openai:gpt-5', name='configured-agent')
|
|
153
|
+
|
|
154
|
+
config = AdapterConfig(
|
|
155
|
+
agent_name='my-agent',
|
|
156
|
+
agent_title='My Agent Title',
|
|
157
|
+
allow_model_selection=True,
|
|
158
|
+
available_models=[
|
|
159
|
+
AdapterModel(
|
|
160
|
+
model_id='fast',
|
|
161
|
+
name='Fast',
|
|
162
|
+
description='Lower-latency responses.',
|
|
163
|
+
override='openai:gpt-5-mini',
|
|
164
|
+
),
|
|
165
|
+
AdapterModel(
|
|
166
|
+
model_id='smart',
|
|
167
|
+
name='Smart',
|
|
168
|
+
description='Higher-quality responses.',
|
|
169
|
+
override='openai:gpt-5',
|
|
170
|
+
),
|
|
171
|
+
],
|
|
172
|
+
capability_bridges=[ThinkingBridge()],
|
|
173
|
+
approval_bridge=NativeApprovalBridge(enable_persistent_choices=True),
|
|
174
|
+
session_store=FileSessionStore(root=Path('.acp-sessions')),
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
run_acp(agent=agent, config=config)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
High-value detail:
|
|
181
|
+
|
|
182
|
+
- `FileSessionStore` takes `root=Path(...)`, not `base_dir=...`
|
|
183
|
+
|
|
184
|
+
## Session Stores
|
|
185
|
+
|
|
186
|
+
ACP Kit currently ships two session stores:
|
|
187
|
+
|
|
188
|
+
- `MemorySessionStore`
|
|
189
|
+
- `FileSessionStore`
|
|
190
|
+
|
|
191
|
+
`MemorySessionStore` is ephemeral. `FileSessionStore` persists ACP sessions across restarts and
|
|
192
|
+
supports:
|
|
193
|
+
|
|
194
|
+
- save
|
|
195
|
+
- get
|
|
196
|
+
- list
|
|
197
|
+
- fork
|
|
198
|
+
- delete
|
|
199
|
+
|
|
200
|
+
Use `FileSessionStore(root=Path(...))` when real ACP clients need durable session state.
|
|
201
|
+
|
|
202
|
+
Current `FileSessionStore` behavior is tuned for durable local-host ACP use:
|
|
203
|
+
|
|
204
|
+
- atomic temp-file write plus replace
|
|
205
|
+
- local process lock and filesystem advisory lock when available
|
|
206
|
+
- malformed saved session files are skipped in public load/list flows
|
|
207
|
+
- stale temp files are cleaned up on startup
|
|
208
|
+
|
|
209
|
+
It is a strong default for editors and single-host services, not a distributed shared-state backend.
|
|
210
|
+
|
|
211
|
+
## Agent Factories And `AgentSource`
|
|
212
|
+
|
|
213
|
+
Use an agent factory when session context changes agent construction but you do not need a full
|
|
214
|
+
custom source object.
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
from pydantic_ai import Agent
|
|
218
|
+
from pydantic_acp import AcpSessionContext, AdapterConfig, run_acp
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def build_agent(session: AcpSessionContext) -> Agent[None, str]:
|
|
222
|
+
workspace_name = session.cwd.name
|
|
223
|
+
return Agent(
|
|
224
|
+
'openai:gpt-5',
|
|
225
|
+
name=f'agent-{workspace_name}',
|
|
226
|
+
instructions=f'You are working in {workspace_name}.',
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
run_acp(
|
|
231
|
+
agent_factory=build_agent,
|
|
232
|
+
config=AdapterConfig(agent_name='factory-agent'),
|
|
233
|
+
)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Use `AgentSource` when you need full control over both the agent and the dependency object:
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
from dataclasses import dataclass
|
|
240
|
+
|
|
241
|
+
from pydantic_ai import Agent
|
|
242
|
+
from pydantic_acp import AcpSessionContext, AgentSource, AdapterConfig, run_acp
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@dataclass(frozen=True, slots=True)
|
|
246
|
+
class Deps:
|
|
247
|
+
workspace_name: str
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class WorkspaceSource(AgentSource[Deps]):
|
|
251
|
+
async def get_agent(self, session: AcpSessionContext) -> Agent[Deps, str]:
|
|
252
|
+
return Agent(
|
|
253
|
+
'openai:gpt-5',
|
|
254
|
+
name='workspace-agent',
|
|
255
|
+
instructions='Use the provided workspace dependencies.',
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
async def get_deps(self, session: AcpSessionContext) -> Deps:
|
|
259
|
+
return Deps(workspace_name=session.cwd.name)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
run_acp(
|
|
263
|
+
agent_source=WorkspaceSource(),
|
|
264
|
+
config=AdapterConfig(agent_name='workspace-agent'),
|
|
265
|
+
)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Reach for `AgentSource` in production-style examples where:
|
|
269
|
+
|
|
270
|
+
- session cwd matters
|
|
271
|
+
- model ids or modes come from the host
|
|
272
|
+
- tools depend on host-backed services
|
|
273
|
+
- you need a richer dependency object than the adapter can infer on its own
|
|
274
|
+
|
|
275
|
+
## Models, Modes, And Slash Commands
|
|
276
|
+
|
|
277
|
+
ACP Kit can expose session-local model and mode switching through two different ownership paths.
|
|
278
|
+
|
|
279
|
+
### Built-in model selection
|
|
280
|
+
|
|
281
|
+
Use built-in model selection when the adapter can own the available model set:
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
from pydantic_acp import AdapterConfig, AdapterModel
|
|
285
|
+
|
|
286
|
+
config = AdapterConfig(
|
|
287
|
+
allow_model_selection=True,
|
|
288
|
+
available_models=[
|
|
289
|
+
AdapterModel(
|
|
290
|
+
model_id='fast',
|
|
291
|
+
name='Fast',
|
|
292
|
+
description='Lower latency.',
|
|
293
|
+
override='openai:gpt-5-mini',
|
|
294
|
+
),
|
|
295
|
+
AdapterModel(
|
|
296
|
+
model_id='smart',
|
|
297
|
+
name='Smart',
|
|
298
|
+
description='Higher quality.',
|
|
299
|
+
override='openai:gpt-5',
|
|
300
|
+
),
|
|
301
|
+
],
|
|
302
|
+
)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Provider-owned model or mode state
|
|
306
|
+
|
|
307
|
+
Use providers when the host already owns that state:
|
|
308
|
+
|
|
309
|
+
- `SessionModelsProvider`
|
|
310
|
+
- `SessionModesProvider`
|
|
311
|
+
- `ConfigOptionsProvider`
|
|
312
|
+
|
|
313
|
+
Mode slash commands are dynamic. They are derived from the configured mode ids rather than from a
|
|
314
|
+
hard-coded global set.
|
|
315
|
+
|
|
316
|
+
Important guardrail:
|
|
317
|
+
|
|
318
|
+
- mode ids must not collide with reserved slash-command names such as `model`, `thinking`,
|
|
319
|
+
`tools`, `hooks`, or `mcp-servers`
|
|
320
|
+
|
|
321
|
+
## Capability Bridges
|
|
322
|
+
|
|
323
|
+
Capability bridges are how ACP-visible runtime behavior gets added without hard-coding everything
|
|
324
|
+
into the adapter core.
|
|
325
|
+
|
|
326
|
+
Common bridges:
|
|
327
|
+
|
|
328
|
+
- `PrepareToolsBridge`
|
|
329
|
+
- `ThinkingBridge`
|
|
330
|
+
- `McpBridge`
|
|
331
|
+
- `HookBridge`
|
|
332
|
+
- `HistoryProcessorBridge`
|
|
333
|
+
|
|
334
|
+
Use `PrepareToolsBridge` to define dynamic modes and tool surfaces:
|
|
335
|
+
|
|
336
|
+
```python
|
|
337
|
+
from pydantic_acp import PrepareToolsBridge, PrepareToolsMode
|
|
338
|
+
from pydantic_ai.tools import RunContext, ToolDefinition
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def ask_tools(
|
|
342
|
+
ctx: RunContext[None],
|
|
343
|
+
tool_defs: list[ToolDefinition],
|
|
344
|
+
) -> list[ToolDefinition]:
|
|
345
|
+
del ctx
|
|
346
|
+
return [tool_def for tool_def in tool_defs if not tool_def.name.startswith('write_')]
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def agent_tools(
|
|
350
|
+
ctx: RunContext[None],
|
|
351
|
+
tool_defs: list[ToolDefinition],
|
|
352
|
+
) -> list[ToolDefinition]:
|
|
353
|
+
del ctx
|
|
354
|
+
return list(tool_defs)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
bridge = PrepareToolsBridge(
|
|
358
|
+
default_mode_id='ask',
|
|
359
|
+
modes=[
|
|
360
|
+
PrepareToolsMode(
|
|
361
|
+
id='ask',
|
|
362
|
+
name='Ask',
|
|
363
|
+
description='Read-only inspection mode.',
|
|
364
|
+
prepare_func=ask_tools,
|
|
365
|
+
),
|
|
366
|
+
PrepareToolsMode(
|
|
367
|
+
id='plan',
|
|
368
|
+
name='Plan',
|
|
369
|
+
description='Native ACP plan mode.',
|
|
370
|
+
prepare_func=ask_tools,
|
|
371
|
+
plan_mode=True,
|
|
372
|
+
),
|
|
373
|
+
PrepareToolsMode(
|
|
374
|
+
id='agent',
|
|
375
|
+
name='Agent',
|
|
376
|
+
description='Full tool surface.',
|
|
377
|
+
prepare_func=agent_tools,
|
|
378
|
+
plan_tools=True,
|
|
379
|
+
),
|
|
380
|
+
],
|
|
381
|
+
)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
High-value guardrails:
|
|
385
|
+
|
|
386
|
+
- only one `PrepareToolsMode(..., plan_mode=True)` is allowed
|
|
387
|
+
- `plan_tools=True` is how a non-plan execution mode keeps plan progress tools visible
|
|
388
|
+
- `ThinkingBridge()` is what makes `/thinking` and the ACP-visible effort selector exist
|
|
389
|
+
- `HookBridge(hide_all=True)` suppresses hook listing output without removing the hook seam itself
|
|
390
|
+
- custom `run_event_stream` hooks or wrappers must return an async iterable; returning a coroutine will break stream execution
|
|
391
|
+
|
|
392
|
+
## Plans, Approvals, Cancellation, And Host Tools
|
|
393
|
+
|
|
394
|
+
Native ACP plan state is separate from provider-owned plan state.
|
|
395
|
+
|
|
396
|
+
Use native plan state when you want the adapter to own the ACP-visible plan lifecycle. Use
|
|
397
|
+
`PlanProvider` when the host should remain the source of truth.
|
|
398
|
+
|
|
399
|
+
Current plan behavior to remember:
|
|
400
|
+
|
|
401
|
+
- `plan_mode=True` exposes native ACP plan creation tools
|
|
402
|
+
- `plan_tools=True` lets execution modes keep plan progress tools visible
|
|
403
|
+
- native plan persistence can be mirrored outward through `NativePlanPersistenceProvider`
|
|
404
|
+
|
|
405
|
+
Approval behavior:
|
|
406
|
+
|
|
407
|
+
- `NativeApprovalBridge` powers the live ACP approval flow
|
|
408
|
+
- `ApprovalStateProvider` exposes extra approval metadata when the host already owns approval state
|
|
409
|
+
|
|
410
|
+
Cancellation behavior:
|
|
411
|
+
|
|
412
|
+
- ACP cancellation is wired through the runtime now
|
|
413
|
+
- cancellation preserves session state and transcript integrity instead of leaving the session in a broken partial state
|
|
414
|
+
|
|
415
|
+
Host-backed tools:
|
|
416
|
+
|
|
417
|
+
- ACP Kit can expose client-backed filesystem and shell helpers
|
|
418
|
+
- projection maps change how tools are rendered in ACP clients without changing the underlying tool contract
|
|
419
|
+
|
|
420
|
+
### HostAccessPolicy
|
|
421
|
+
|
|
422
|
+
`HostAccessPolicy` is ACP Kit's native typed guardrail surface for host-backed filesystem and terminal access.
|
|
423
|
+
|
|
424
|
+
Reach for it first when an integration has started inventing ad hoc rules such as:
|
|
425
|
+
|
|
426
|
+
- "warn for absolute paths but deny workspace escapes"
|
|
427
|
+
- "show one caution in the client but enforce a different rule in the backend"
|
|
428
|
+
- "treat command cwd and file paths as unrelated policy domains"
|
|
429
|
+
|
|
430
|
+
Use it:
|
|
431
|
+
|
|
432
|
+
- when host-backed file and terminal tools already exist
|
|
433
|
+
- when approvals or projection warnings need to describe the same risk model that enforcement uses
|
|
434
|
+
- when downstream code has started to accumulate one-off path checks
|
|
435
|
+
|
|
436
|
+
Do not reach for it:
|
|
437
|
+
|
|
438
|
+
- when the integration does not expose host-backed file or terminal tools at all
|
|
439
|
+
- when the problem is product-specific approval wording rather than reusable access policy
|
|
440
|
+
|
|
441
|
+
Use it when an integration needs one reusable place to decide:
|
|
442
|
+
|
|
443
|
+
- whether absolute paths should only warn or hard fail
|
|
444
|
+
- whether paths outside the active session cwd should warn or deny
|
|
445
|
+
- whether workspace-root escapes should always deny
|
|
446
|
+
- whether command cwd and command path arguments should follow the same policy language as file paths
|
|
447
|
+
|
|
448
|
+
Important distinction:
|
|
449
|
+
|
|
450
|
+
- `evaluate_path(...)` and `evaluate_command(...)` are for UI and approval surfaces
|
|
451
|
+
- `enforce_path(...)` and `enforce_command(...)` are for actual blocking before ACP host requests are sent
|
|
452
|
+
|
|
453
|
+
The evaluation objects are intentionally UI-friendly. They expose:
|
|
454
|
+
|
|
455
|
+
- `disposition`
|
|
456
|
+
- `headline`
|
|
457
|
+
- `message`
|
|
458
|
+
- `recommendation`
|
|
459
|
+
- `risks`
|
|
460
|
+
- `risk_codes`
|
|
461
|
+
- `primary_risk`
|
|
462
|
+
- `summary_lines()`
|
|
463
|
+
|
|
464
|
+
That means downstream integrations do not need to invent their own warning strings just to show a clear caution card.
|
|
465
|
+
|
|
466
|
+
Typical use:
|
|
467
|
+
|
|
468
|
+
```python
|
|
469
|
+
from pydantic_acp import ClientHostContext, HostAccessPolicy
|
|
470
|
+
|
|
471
|
+
policy = HostAccessPolicy.strict()
|
|
472
|
+
|
|
473
|
+
host = ClientHostContext.from_session(
|
|
474
|
+
client=client,
|
|
475
|
+
session=session,
|
|
476
|
+
access_policy=policy,
|
|
477
|
+
workspace_root=session.cwd,
|
|
478
|
+
)
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
Small verified evaluation example:
|
|
482
|
+
|
|
483
|
+
```python
|
|
484
|
+
from pathlib import Path
|
|
485
|
+
|
|
486
|
+
from pydantic_acp import HostAccessPolicy
|
|
487
|
+
|
|
488
|
+
policy = HostAccessPolicy.strict()
|
|
489
|
+
evaluation = policy.evaluate_path(
|
|
490
|
+
'../notes.txt',
|
|
491
|
+
session_cwd=Path('/workspace/app'),
|
|
492
|
+
workspace_root=Path('/workspace/app'),
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
assert evaluation.disposition == 'deny'
|
|
496
|
+
assert evaluation.should_deny
|
|
497
|
+
assert 'outside_cwd' in evaluation.risk_codes
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
Current presets:
|
|
501
|
+
|
|
502
|
+
- `HostAccessPolicy()` is conservative default behavior
|
|
503
|
+
- `HostAccessPolicy.strict()` denies more aggressively outside the active cwd
|
|
504
|
+
- `HostAccessPolicy.permissive()` keeps more paths executable but still surfaces risk
|
|
505
|
+
|
|
506
|
+
Current scope:
|
|
507
|
+
|
|
508
|
+
- file path evaluation
|
|
509
|
+
- command cwd evaluation
|
|
510
|
+
- heuristic detection of obvious path-like command arguments
|
|
511
|
+
- native backend-side deny enforcement
|
|
512
|
+
|
|
513
|
+
Current limit:
|
|
514
|
+
|
|
515
|
+
- it is not a full shell parser
|
|
516
|
+
- it does not automatically wire itself through every integration seam yet
|
|
517
|
+
|
|
518
|
+
Primary references:
|
|
519
|
+
|
|
520
|
+
- [Host Backends and Projections](https://vcoderun.github.io/acpkit/host-backends/)
|
|
521
|
+
- [Projection Cookbook](https://vcoderun.github.io/acpkit/projection-cookbook/)
|
|
522
|
+
|
|
523
|
+
## Black-box Integration Harness
|
|
524
|
+
|
|
525
|
+
`BlackBoxHarness` exists so downstream integrations can prove the ACP boundary without rebuilding test plumbing from scratch.
|
|
526
|
+
|
|
527
|
+
Reach for it when the integration already "works" but still lacks proof for:
|
|
528
|
+
|
|
529
|
+
- approval replay
|
|
530
|
+
- host-backed side effects
|
|
531
|
+
- session reload correctness
|
|
532
|
+
- ACP-visible transcript truthfulness
|
|
533
|
+
|
|
534
|
+
Use it:
|
|
535
|
+
|
|
536
|
+
- after the integration already has a real adapter construction seam
|
|
537
|
+
- when you need one reusable way to drive approvals, prompts, reloads, and visible updates
|
|
538
|
+
- when a normal unit test would miss ACP-visible behavior
|
|
539
|
+
|
|
540
|
+
Do not use it:
|
|
541
|
+
|
|
542
|
+
- to inspect private helper ordering
|
|
543
|
+
- as a substitute for product-level end-to-end testing
|
|
544
|
+
- before the integration has a coherent ownership model for sessions, approvals, and host tools
|
|
545
|
+
|
|
546
|
+
Use it when you want to verify:
|
|
547
|
+
|
|
548
|
+
- session create/load behavior
|
|
549
|
+
- visible ACP updates
|
|
550
|
+
- approval roundtrips
|
|
551
|
+
- host-backed file or terminal flows
|
|
552
|
+
- replay after reload
|
|
553
|
+
|
|
554
|
+
What it gives you:
|
|
555
|
+
|
|
556
|
+
- adapter construction plus a recording ACP client in one object
|
|
557
|
+
- `new_session(...)`
|
|
558
|
+
- `load_session(...)`
|
|
559
|
+
- `prompt_text(...)`
|
|
560
|
+
- `set_mode(...)`
|
|
561
|
+
- `set_model(...)`
|
|
562
|
+
- permission response queueing helpers
|
|
563
|
+
- update filtering
|
|
564
|
+
- reconstructed agent messages
|
|
565
|
+
|
|
566
|
+
Typical use:
|
|
567
|
+
|
|
568
|
+
```python
|
|
569
|
+
import asyncio
|
|
570
|
+
|
|
571
|
+
from pydantic_acp import AdapterConfig, BlackBoxHarness, FileSessionStore
|
|
572
|
+
|
|
573
|
+
harness = BlackBoxHarness.create(
|
|
574
|
+
agent_factory=build_agent,
|
|
575
|
+
config=AdapterConfig(session_store=FileSessionStore(tmp_path / 'sessions')),
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
session = asyncio.run(harness.new_session(cwd=str(tmp_path)))
|
|
579
|
+
harness.queue_permission_selected('allow_once')
|
|
580
|
+
response = asyncio.run(harness.prompt_text('Write the workspace note.'))
|
|
581
|
+
|
|
582
|
+
assert response.stop_reason == 'end_turn'
|
|
583
|
+
assert harness.tool_updates(session_id=session.session_id)
|
|
584
|
+
assert harness.agent_messages(session_id=session.session_id)
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
Small verified example from the harness test shape:
|
|
588
|
+
|
|
589
|
+
```python
|
|
590
|
+
session = asyncio.run(harness.new_session(cwd=str(tmp_path)))
|
|
591
|
+
harness.queue_permission_selected('allow_once')
|
|
592
|
+
response = asyncio.run(harness.prompt_text('Write the workspace note.'))
|
|
593
|
+
|
|
594
|
+
assert response.stop_reason == 'end_turn'
|
|
595
|
+
assert harness.agent_messages(session_id=session.session_id) == ['done']
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
The harness is intentionally black-box.
|
|
599
|
+
|
|
600
|
+
Prefer asserting on:
|
|
601
|
+
|
|
602
|
+
- ACP return values
|
|
603
|
+
- emitted `ToolCallStart` / `ToolCallProgress` updates
|
|
604
|
+
- reconstructed visible messages
|
|
605
|
+
- persisted replay behavior
|
|
606
|
+
- real host-backed side effects
|
|
607
|
+
|
|
608
|
+
Do not use it to:
|
|
609
|
+
|
|
610
|
+
- inspect private helper choreography
|
|
611
|
+
- lock internal runtime call order
|
|
612
|
+
- replace product-level end-to-end tests
|
|
613
|
+
|
|
614
|
+
Good default scenario ladder for a new integration:
|
|
615
|
+
|
|
616
|
+
1. session create -> prompt -> reload
|
|
617
|
+
2. approval required -> allow once
|
|
618
|
+
3. approval required -> deny once
|
|
619
|
+
4. host-backed file read/write
|
|
620
|
+
5. host-backed terminal execution
|
|
621
|
+
6. mode switch changes behavior
|
|
622
|
+
7. model switch changes session-local state
|
|
623
|
+
|
|
624
|
+
Primary references:
|
|
625
|
+
|
|
626
|
+
- [Integration Testing](https://vcoderun.github.io/acpkit/integration-testing/)
|
|
627
|
+
- [Examples Overview](https://vcoderun.github.io/acpkit/examples/)
|
|
628
|
+
|
|
629
|
+
## Projection Maps And Hook Rendering
|
|
630
|
+
|
|
631
|
+
Projection maps make ACP clients see richer file or command behavior than a raw generic tool card.
|
|
632
|
+
|
|
633
|
+
Common maps:
|
|
634
|
+
|
|
635
|
+
- filesystem maps
|
|
636
|
+
- bash / command maps
|
|
637
|
+
- hook projection maps
|
|
638
|
+
|
|
639
|
+
Use them when the client should see more structured output, but avoid pretending a tool is
|
|
640
|
+
something it is not.
|
|
641
|
+
|
|
642
|
+
### Projection Helper Primitives
|
|
643
|
+
|
|
644
|
+
ACP Kit now also ships small reusable projection helpers for integrations that need consistent shaping but do not want to rebuild truncation and warning logic repeatedly.
|
|
645
|
+
|
|
646
|
+
High-value helpers:
|
|
647
|
+
|
|
648
|
+
- `truncate_text(...)`
|
|
649
|
+
- `truncate_lines(...)`
|
|
650
|
+
- `single_line_summary(...)`
|
|
651
|
+
- `format_code_block(...)`
|
|
652
|
+
- `format_diff_preview(...)`
|
|
653
|
+
- `format_terminal_status(...)`
|
|
654
|
+
- `caution_for_path(...)`
|
|
655
|
+
- `caution_for_command(...)`
|
|
656
|
+
|
|
657
|
+
Use these helpers when:
|
|
658
|
+
|
|
659
|
+
- a chat client needs a plain-text diff preview
|
|
660
|
+
- command titles should stay compact and consistent
|
|
661
|
+
- long stdout/stderr content needs predictable truncation
|
|
662
|
+
- caution text should come from the same `HostAccessPolicy` evaluation model as backend enforcement
|
|
663
|
+
|
|
664
|
+
These helpers are intentionally small. They are building blocks, not a full rendering framework.
|
|
665
|
+
|
|
666
|
+
## Examples That Matter
|
|
667
|
+
|
|
668
|
+
High-value maintained examples live under `examples/pydantic/`:
|
|
669
|
+
|
|
670
|
+
| Example | Purpose |
|
|
671
|
+
| --- | --- |
|
|
672
|
+
| [`examples/pydantic/acp_agent.py`](https://github.com/vcoderun/acpkit/blob/main/examples/pydantic/acp_agent.py) | smallest direct `run_acp(...)` path |
|
|
673
|
+
| [`examples/pydantic/factory_agent.py`](https://github.com/vcoderun/acpkit/blob/main/examples/pydantic/factory_agent.py) | session-aware factory |
|
|
674
|
+
| [`examples/pydantic/providers.py`](https://github.com/vcoderun/acpkit/blob/main/examples/pydantic/providers.py) | host-owned models, modes, config, plan, and approval metadata |
|
|
675
|
+
| [`examples/pydantic/approvals.py`](https://github.com/vcoderun/acpkit/blob/main/examples/pydantic/approvals.py) | deferred approval flow |
|
|
676
|
+
| [`examples/pydantic/bridges.py`](https://github.com/vcoderun/acpkit/blob/main/examples/pydantic/bridges.py) | bridge builder and ACP-visible capabilities |
|
|
677
|
+
| [`examples/pydantic/host_context.py`](https://github.com/vcoderun/acpkit/blob/main/examples/pydantic/host_context.py) | client-backed filesystem and terminal helpers |
|
|
678
|
+
| [`examples/pydantic/hook_projection.py`](https://github.com/vcoderun/acpkit/blob/main/examples/pydantic/hook_projection.py) | hook rendering and `HookProjectionMap` behavior |
|
|
679
|
+
| [`examples/pydantic/strong_agent.py`](https://github.com/vcoderun/acpkit/blob/main/examples/pydantic/strong_agent.py) | production-style workspace coding-agent showcase |
|
|
680
|
+
| [`examples/pydantic/strong_agent_v2.py`](https://github.com/vcoderun/acpkit/blob/main/examples/pydantic/strong_agent_v2.py) | alternative workspace integration shape |
|
|
681
|
+
|
|
682
|
+
Use [`strong_agent.py`](https://github.com/vcoderun/acpkit/blob/main/examples/pydantic/strong_agent.py) when the docs or code need to highlight:
|
|
683
|
+
|
|
684
|
+
- mode-aware tool shaping
|
|
685
|
+
- provider-owned model and mode state
|
|
686
|
+
- native plan persistence
|
|
687
|
+
- host-backed tools
|
|
688
|
+
- MCP metadata mapping
|
|
689
|
+
- bridge composition
|
|
690
|
+
- projection maps
|
|
691
|
+
- final `create_acp_agent(...)` assembly
|
|
692
|
+
|
|
693
|
+
## Documentation Sources
|
|
694
|
+
|
|
695
|
+
High-value docs pages:
|
|
696
|
+
|
|
697
|
+
- [ACP Kit Overview](https://vcoderun.github.io/acpkit/)
|
|
698
|
+
- [Pydantic ACP Overview](https://vcoderun.github.io/acpkit/pydantic-acp/)
|
|
699
|
+
- [AdapterConfig](https://vcoderun.github.io/acpkit/pydantic-acp/adapter-config/)
|
|
700
|
+
- [Session State and Lifecycle](https://vcoderun.github.io/acpkit/pydantic-acp/session-state/)
|
|
701
|
+
- [Models, Modes, and Slash Commands](https://vcoderun.github.io/acpkit/pydantic-acp/runtime-controls/)
|
|
702
|
+
- [Plans, Thinking, and Approvals](https://vcoderun.github.io/acpkit/pydantic-acp/plans-thinking-approvals/)
|
|
703
|
+
- [Providers](https://vcoderun.github.io/acpkit/providers/)
|
|
704
|
+
- [Bridges](https://vcoderun.github.io/acpkit/bridges/)
|
|
705
|
+
- [Host Backends and Projections](https://vcoderun.github.io/acpkit/host-backends/)
|
|
706
|
+
- [Integration Testing](https://vcoderun.github.io/acpkit/integration-testing/)
|
|
707
|
+
- [Projection Cookbook](https://vcoderun.github.io/acpkit/projection-cookbook/)
|
|
708
|
+
- [Examples Overview](https://vcoderun.github.io/acpkit/examples/)
|
|
709
|
+
- [Workspace Agent](https://vcoderun.github.io/acpkit/examples/workspace-agent/)
|
|
710
|
+
- [pydantic_acp API](https://vcoderun.github.io/acpkit/api/pydantic_acp/)
|
|
711
|
+
|
|
712
|
+
## Compatibility Manifest
|
|
713
|
+
|
|
714
|
+
ACP Kit now also ships a typed root-level compatibility manifest schema through `acpkit`.
|
|
715
|
+
|
|
716
|
+
Reach for it after the integration already has real seams and at least one black-box proof path.
|
|
717
|
+
|
|
718
|
+
Do not use it as a speculative roadmap scratchpad. Use it as a reviewable declaration of what is actually wired today.
|
|
719
|
+
|
|
720
|
+
Use it:
|
|
721
|
+
|
|
722
|
+
- after at least one black-box proof path exists
|
|
723
|
+
- when reviews need one typed declaration of supported ACP surfaces
|
|
724
|
+
- when docs should be generated from validated code instead of prose drift
|
|
725
|
+
|
|
726
|
+
Do not use it:
|
|
727
|
+
|
|
728
|
+
- before the integration can already demonstrate the behavior it claims
|
|
729
|
+
- as a replacement for proof tests
|
|
730
|
+
- as a vague backlog matrix with no mapping seam
|
|
731
|
+
|
|
732
|
+
Use it when a real integration needs one reviewable declaration of:
|
|
733
|
+
|
|
734
|
+
- which ACP surfaces are implemented
|
|
735
|
+
- which are partial
|
|
736
|
+
- which are intentionally not used
|
|
737
|
+
- which are only planned
|
|
738
|
+
|
|
739
|
+
Core types:
|
|
740
|
+
|
|
741
|
+
- `CompatibilityManifest`
|
|
742
|
+
- `SurfaceSupport`
|
|
743
|
+
- `SurfaceStatus`
|
|
744
|
+
- `SurfaceOwner`
|
|
745
|
+
|
|
746
|
+
Typical use:
|
|
747
|
+
|
|
748
|
+
```python
|
|
749
|
+
from acpkit import CompatibilityManifest, SurfaceSupport
|
|
750
|
+
|
|
751
|
+
manifest = CompatibilityManifest(
|
|
752
|
+
integration_name='workspace-agent',
|
|
753
|
+
adapter='pydantic-acp',
|
|
754
|
+
surfaces={
|
|
755
|
+
'session.load': SurfaceSupport(
|
|
756
|
+
status='implemented',
|
|
757
|
+
owner='adapter',
|
|
758
|
+
mapping='FileSessionStore + load_session',
|
|
759
|
+
),
|
|
760
|
+
'mode.switch': SurfaceSupport(
|
|
761
|
+
status='partial',
|
|
762
|
+
owner='bridge',
|
|
763
|
+
mapping='PrepareToolsBridge dynamic modes',
|
|
764
|
+
rationale='Only explicitly exposed runtime modes are surfaced.',
|
|
765
|
+
),
|
|
766
|
+
'authenticate': SurfaceSupport(
|
|
767
|
+
status='planned',
|
|
768
|
+
rationale='No auth handshake has been added yet.',
|
|
769
|
+
),
|
|
770
|
+
},
|
|
771
|
+
)
|
|
772
|
+
|
|
773
|
+
manifest.validate()
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
Minimal review rule:
|
|
777
|
+
|
|
778
|
+
- every `implemented` surface should point to one concrete mapping seam
|
|
779
|
+
- every `partial`, `intentionally_not_used`, and `planned` surface should explain why
|
|
780
|
+
- `mixed` ownership is only acceptable when the split is named explicitly
|
|
781
|
+
|
|
782
|
+
Important rule:
|
|
783
|
+
|
|
784
|
+
- do not generate this from guesses
|
|
785
|
+
- derive it from a real integration audit
|
|
786
|
+
- then validate it in tests
|
|
787
|
+
|
|
788
|
+
Recommended workflow:
|
|
789
|
+
|
|
790
|
+
1. inventory real seams
|
|
791
|
+
2. declare surfaces in code
|
|
792
|
+
3. call `manifest.validate()` in tests or CI
|
|
793
|
+
4. optionally publish `manifest.to_markdown()` into docs
|
|
794
|
+
|
|
795
|
+
This is not a runtime feature. It is an integration review and documentation hygiene feature.
|
|
796
|
+
|
|
797
|
+
Primary reference:
|
|
798
|
+
|
|
799
|
+
- [Compatibility Manifest Guide](https://vcoderun.github.io/acpkit/compatibility-matrix-template/)
|
|
800
|
+
|
|
801
|
+
## Skill-Local Routing Aids
|
|
802
|
+
|
|
803
|
+
These files exist to route you quickly into the right part of the codebase or docs set when the
|
|
804
|
+
task is narrow:
|
|
805
|
+
|
|
806
|
+
- [resources/intro.md](resources/intro.md)
|
|
807
|
+
- [references/package-surface.md](references/package-surface.md)
|
|
808
|
+
- [references/runtime-capabilities.md](references/runtime-capabilities.md)
|
|
809
|
+
- [references/docs-examples-map.md](references/docs-examples-map.md)
|
|
810
|
+
|
|
811
|
+
## Utility Scripts
|
|
812
|
+
|
|
813
|
+
Use the bundled scripts instead of guessing:
|
|
814
|
+
|
|
815
|
+
- `python3.11 .agents/skills/acpkit-sdk/scripts/list_public_exports.py`
|
|
816
|
+
- `python3.11 .agents/skills/acpkit-sdk/scripts/list_examples.py`
|
|
817
|
+
|
|
818
|
+
## Working Rules
|
|
819
|
+
|
|
820
|
+
- Prefer current code over stale memory.
|
|
821
|
+
- If docs and code disagree, trust code first and update docs.
|
|
822
|
+
- Do not invent ACP surface the runtime cannot actually honor.
|
|
823
|
+
- Keep examples runnable, explicit, and strongly typed.
|
|
824
|
+
- Treat adapter-owned state and host-owned state as different design choices.
|
|
825
|
+
- Prefer the narrowest seam that matches the user’s need.
|
|
826
|
+
- Use the compatibility manifest when an integration needs one typed, reviewable ACP surface declaration instead of a loose prose matrix.
|
|
827
|
+
- `FileSessionStore` uses `root=Path(...)`.
|
|
828
|
+
- `FileSessionStore` is the hardened local durable store, not a distributed session backend.
|
|
829
|
+
- Mode slash commands are dynamic, and mode ids must not collide with reserved names such as `model`, `thinking`, `tools`, `hooks`, or `mcp-servers`.
|
|
830
|
+
- `run_event_stream` hooks must return async iterables, not coroutines.
|