agent-handshake 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.
- agent_handshake-0.7.0/.coderabbit.yaml +23 -0
- agent_handshake-0.7.0/.github/ISSUE_TEMPLATE/bug_report.yml +48 -0
- agent_handshake-0.7.0/.github/ISSUE_TEMPLATE/feature_request.yml +30 -0
- agent_handshake-0.7.0/.github/dependabot.yml +28 -0
- agent_handshake-0.7.0/.github/pull_request_template.md +22 -0
- agent_handshake-0.7.0/.github/workflows/ci.yml +71 -0
- agent_handshake-0.7.0/.github/workflows/publish.yml +41 -0
- agent_handshake-0.7.0/.gitignore +151 -0
- agent_handshake-0.7.0/.pre-commit-config.yaml +7 -0
- agent_handshake-0.7.0/CHANGELOG.md +175 -0
- agent_handshake-0.7.0/CONTRIBUTING.md +60 -0
- agent_handshake-0.7.0/LICENSE +191 -0
- agent_handshake-0.7.0/Makefile +26 -0
- agent_handshake-0.7.0/NOTES.md +96 -0
- agent_handshake-0.7.0/PKG-INFO +493 -0
- agent_handshake-0.7.0/README.md +434 -0
- agent_handshake-0.7.0/SECURITY.md +17 -0
- agent_handshake-0.7.0/action.yml +56 -0
- agent_handshake-0.7.0/docs/architecture.md +58 -0
- agent_handshake-0.7.0/docs/ci-integration.md +74 -0
- agent_handshake-0.7.0/docs/cli-reference.md +100 -0
- agent_handshake-0.7.0/docs/concepts.md +33 -0
- agent_handshake-0.7.0/docs/demo.gif +0 -0
- agent_handshake-0.7.0/docs/diagrams/change-workflow.svg +71 -0
- agent_handshake-0.7.0/docs/diagrams/how-it-works.svg +67 -0
- agent_handshake-0.7.0/docs/getting-started.md +8 -0
- agent_handshake-0.7.0/docs/writing-adapters.md +104 -0
- agent_handshake-0.7.0/docs/writing-specs.md +78 -0
- agent_handshake-0.7.0/examples/customer_support/README.md +70 -0
- agent_handshake-0.7.0/examples/customer_support/agents/resolution.py +30 -0
- agent_handshake-0.7.0/examples/customer_support/agents/triage.py +38 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/adapters/__init__.py +9 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/adapters/resolution_adapter.py +13 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/adapters/triage_adapter.py +13 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/handshake.yaml +20 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/scenarios/support_scenarios.yaml +31 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/snapshots/resolution-agent/billing_overcharge_185fe02a5c6f.json +25 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/snapshots/resolution-agent/general_inquiry_08b03d704f62.json +25 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/snapshots/resolution-agent/product_defect_69524abe4d67.json +25 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/snapshots/resolution-agent/shipping_delay_52c779d38d0e.json +25 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/snapshots/triage-agent/billing_overcharge_4701dd165420.json +22 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/snapshots/triage-agent/general_inquiry_01557b92e9af.json +22 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/snapshots/triage-agent/product_defect_165f0478e401.json +22 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/snapshots/triage-agent/shipping_delay_8e770c534edc.json +22 -0
- agent_handshake-0.7.0/examples/customer_support/handshake/specs/triage-to-resolution.yaml +44 -0
- agent_handshake-0.7.0/examples/customer_support/tests/test_specs.py +55 -0
- agent_handshake-0.7.0/pyproject.toml +109 -0
- agent_handshake-0.7.0/scripts/demo_gif.py +239 -0
- agent_handshake-0.7.0/src/agent_handshake/__init__.py +74 -0
- agent_handshake-0.7.0/src/agent_handshake/_internal/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/_internal/hashing.py +23 -0
- agent_handshake-0.7.0/src/agent_handshake/_internal/safe_eval.py +119 -0
- agent_handshake-0.7.0/src/agent_handshake/_internal/types.py +14 -0
- agent_handshake-0.7.0/src/agent_handshake/adapters/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/adapters/a2a_adapter.py +256 -0
- agent_handshake-0.7.0/src/agent_handshake/adapters/base.py +68 -0
- agent_handshake-0.7.0/src/agent_handshake/adapters/function_adapter.py +83 -0
- agent_handshake-0.7.0/src/agent_handshake/adapters/http_adapter.py +105 -0
- agent_handshake-0.7.0/src/agent_handshake/adapters/langchain_adapter.py +94 -0
- agent_handshake-0.7.0/src/agent_handshake/cli/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/cli/diff_cmd.py +132 -0
- agent_handshake-0.7.0/src/agent_handshake/cli/infer_cmd.py +140 -0
- agent_handshake-0.7.0/src/agent_handshake/cli/init_cmd.py +179 -0
- agent_handshake-0.7.0/src/agent_handshake/cli/main.py +100 -0
- agent_handshake-0.7.0/src/agent_handshake/cli/pipeline_cmd.py +175 -0
- agent_handshake-0.7.0/src/agent_handshake/cli/record_cmd.py +123 -0
- agent_handshake-0.7.0/src/agent_handshake/cli/skill_cmd.py +46 -0
- agent_handshake-0.7.0/src/agent_handshake/cli/test_cmd.py +279 -0
- agent_handshake-0.7.0/src/agent_handshake/config/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/config/loader.py +63 -0
- agent_handshake-0.7.0/src/agent_handshake/config/settings.py +41 -0
- agent_handshake-0.7.0/src/agent_handshake/diff/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/diff/engine.py +129 -0
- agent_handshake-0.7.0/src/agent_handshake/diff/report.py +53 -0
- agent_handshake-0.7.0/src/agent_handshake/diff/semantic.py +98 -0
- agent_handshake-0.7.0/src/agent_handshake/diff/structural.py +96 -0
- agent_handshake-0.7.0/src/agent_handshake/exceptions.py +87 -0
- agent_handshake-0.7.0/src/agent_handshake/infer/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/infer/builder.py +155 -0
- agent_handshake-0.7.0/src/agent_handshake/infer/check.py +97 -0
- agent_handshake-0.7.0/src/agent_handshake/infer/consumer.py +276 -0
- agent_handshake-0.7.0/src/agent_handshake/pipeline/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/pipeline/dag.py +165 -0
- agent_handshake-0.7.0/src/agent_handshake/pipeline/executor.py +166 -0
- agent_handshake-0.7.0/src/agent_handshake/pipeline/trace.py +68 -0
- agent_handshake-0.7.0/src/agent_handshake/policy/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/policy/builtin.py +59 -0
- agent_handshake-0.7.0/src/agent_handshake/policy/custom.py +57 -0
- agent_handshake-0.7.0/src/agent_handshake/policy/engine.py +153 -0
- agent_handshake-0.7.0/src/agent_handshake/project.py +118 -0
- agent_handshake-0.7.0/src/agent_handshake/py.typed +1 -0
- agent_handshake-0.7.0/src/agent_handshake/pytest_plugin.py +219 -0
- agent_handshake-0.7.0/src/agent_handshake/reporting/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/reporting/console.py +143 -0
- agent_handshake-0.7.0/src/agent_handshake/reporting/github.py +110 -0
- agent_handshake-0.7.0/src/agent_handshake/reporting/junit.py +57 -0
- agent_handshake-0.7.0/src/agent_handshake/reporting/markdown.py +55 -0
- agent_handshake-0.7.0/src/agent_handshake/semantic/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/semantic/embeddings.py +50 -0
- agent_handshake-0.7.0/src/agent_handshake/semantic/engine.py +126 -0
- agent_handshake-0.7.0/src/agent_handshake/semantic/similarity.py +31 -0
- agent_handshake-0.7.0/src/agent_handshake/skill/SKILL.md +109 -0
- agent_handshake-0.7.0/src/agent_handshake/snapshot/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/snapshot/baseline.py +77 -0
- agent_handshake-0.7.0/src/agent_handshake/snapshot/fingerprint.py +56 -0
- agent_handshake-0.7.0/src/agent_handshake/snapshot/recorder.py +69 -0
- agent_handshake-0.7.0/src/agent_handshake/snapshot/replay.py +50 -0
- agent_handshake-0.7.0/src/agent_handshake/snapshot/store.py +199 -0
- agent_handshake-0.7.0/src/agent_handshake/spec/__init__.py +1 -0
- agent_handshake-0.7.0/src/agent_handshake/spec/checker.py +101 -0
- agent_handshake-0.7.0/src/agent_handshake/spec/loader.py +90 -0
- agent_handshake-0.7.0/src/agent_handshake/spec/registry.py +50 -0
- agent_handshake-0.7.0/src/agent_handshake/spec/schema.py +89 -0
- agent_handshake-0.7.0/src/agent_handshake/spec/validator.py +83 -0
- agent_handshake-0.7.0/tests/__init__.py +1 -0
- agent_handshake-0.7.0/tests/conftest.py +93 -0
- agent_handshake-0.7.0/tests/test_a2a_interop.py +175 -0
- agent_handshake-0.7.0/tests/test_adapters_a2a.py +284 -0
- agent_handshake-0.7.0/tests/test_adapters_function.py +73 -0
- agent_handshake-0.7.0/tests/test_adapters_http.py +67 -0
- agent_handshake-0.7.0/tests/test_adapters_langchain.py +59 -0
- agent_handshake-0.7.0/tests/test_cli_diff.py +169 -0
- agent_handshake-0.7.0/tests/test_cli_infer.py +209 -0
- agent_handshake-0.7.0/tests/test_cli_init.py +98 -0
- agent_handshake-0.7.0/tests/test_cli_pipeline.py +203 -0
- agent_handshake-0.7.0/tests/test_cli_record.py +202 -0
- agent_handshake-0.7.0/tests/test_cli_test.py +362 -0
- agent_handshake-0.7.0/tests/test_config_loader.py +64 -0
- agent_handshake-0.7.0/tests/test_diff_semantic.py +43 -0
- agent_handshake-0.7.0/tests/test_diff_structural.py +77 -0
- agent_handshake-0.7.0/tests/test_exceptions.py +213 -0
- agent_handshake-0.7.0/tests/test_infer_builder.py +151 -0
- agent_handshake-0.7.0/tests/test_infer_check.py +117 -0
- agent_handshake-0.7.0/tests/test_infer_consumer.py +167 -0
- agent_handshake-0.7.0/tests/test_pipeline_dag.py +92 -0
- agent_handshake-0.7.0/tests/test_pipeline_executor.py +70 -0
- agent_handshake-0.7.0/tests/test_policy_builtin.py +49 -0
- agent_handshake-0.7.0/tests/test_policy_engine.py +61 -0
- agent_handshake-0.7.0/tests/test_pytest_plugin.py +179 -0
- agent_handshake-0.7.0/tests/test_reporting_console.py +57 -0
- agent_handshake-0.7.0/tests/test_reporting_markdown.py +57 -0
- agent_handshake-0.7.0/tests/test_safe_eval.py +122 -0
- agent_handshake-0.7.0/tests/test_semantic_engine.py +92 -0
- agent_handshake-0.7.0/tests/test_skill.py +97 -0
- agent_handshake-0.7.0/tests/test_snapshot_fingerprint.py +46 -0
- agent_handshake-0.7.0/tests/test_snapshot_replay.py +52 -0
- agent_handshake-0.7.0/tests/test_snapshot_store.py +187 -0
- agent_handshake-0.7.0/tests/test_spec_loader.py +93 -0
- agent_handshake-0.7.0/tests/test_spec_validator.py +111 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
|
|
2
|
+
language: en-US
|
|
3
|
+
|
|
4
|
+
reviews:
|
|
5
|
+
profile: chill
|
|
6
|
+
request_changes_workflow: false
|
|
7
|
+
high_level_summary: true
|
|
8
|
+
review_status: true
|
|
9
|
+
collapse_walkthrough: true
|
|
10
|
+
poem: false
|
|
11
|
+
sequence_diagrams: false
|
|
12
|
+
# Review the shipped code and its tests; docs, examples and assets are skipped.
|
|
13
|
+
path_filters:
|
|
14
|
+
- "src/**"
|
|
15
|
+
- "tests/**"
|
|
16
|
+
- "action.yml"
|
|
17
|
+
- ".github/workflows/**"
|
|
18
|
+
auto_review:
|
|
19
|
+
enabled: true
|
|
20
|
+
drafts: false
|
|
21
|
+
|
|
22
|
+
chat:
|
|
23
|
+
auto_reply: true
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something is broken or behaving unexpectedly.
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for taking the time to report a bug. Please fill in as much as you can.
|
|
9
|
+
|
|
10
|
+
- type: input
|
|
11
|
+
id: version
|
|
12
|
+
attributes:
|
|
13
|
+
label: agent-handshake version
|
|
14
|
+
placeholder: "0.7.0"
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
|
|
18
|
+
- type: input
|
|
19
|
+
id: python
|
|
20
|
+
attributes:
|
|
21
|
+
label: Python version
|
|
22
|
+
placeholder: "3.12"
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: description
|
|
28
|
+
attributes:
|
|
29
|
+
label: Description
|
|
30
|
+
description: What happened? What did you expect to happen?
|
|
31
|
+
validations:
|
|
32
|
+
required: true
|
|
33
|
+
|
|
34
|
+
- type: textarea
|
|
35
|
+
id: repro
|
|
36
|
+
attributes:
|
|
37
|
+
label: Minimal reproduction
|
|
38
|
+
description: The smallest code / config that triggers the issue.
|
|
39
|
+
render: python
|
|
40
|
+
validations:
|
|
41
|
+
required: true
|
|
42
|
+
|
|
43
|
+
- type: textarea
|
|
44
|
+
id: traceback
|
|
45
|
+
attributes:
|
|
46
|
+
label: Traceback
|
|
47
|
+
description: Paste the full error output here (if any).
|
|
48
|
+
render: text
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Propose a new feature or improvement.
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Before submitting, search open issues to avoid duplicates.
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: problem
|
|
12
|
+
attributes:
|
|
13
|
+
label: Problem
|
|
14
|
+
description: What problem does this solve? What use case is blocked without it?
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: proposal
|
|
20
|
+
attributes:
|
|
21
|
+
label: Proposed solution
|
|
22
|
+
description: What should the feature look like? API sketches, CLI flags, config keys — whatever helps.
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: alternatives
|
|
28
|
+
attributes:
|
|
29
|
+
label: Alternatives considered
|
|
30
|
+
description: What workarounds exist today? Why are they insufficient?
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: pip
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
day: monday
|
|
8
|
+
groups:
|
|
9
|
+
dev-deps:
|
|
10
|
+
patterns:
|
|
11
|
+
- "ruff"
|
|
12
|
+
- "mypy"
|
|
13
|
+
- "pytest*"
|
|
14
|
+
- "pre-commit"
|
|
15
|
+
core-deps:
|
|
16
|
+
patterns:
|
|
17
|
+
- "typer"
|
|
18
|
+
- "rich"
|
|
19
|
+
- "pyyaml"
|
|
20
|
+
- "pydantic"
|
|
21
|
+
- "jsonschema"
|
|
22
|
+
- "httpx"
|
|
23
|
+
|
|
24
|
+
- package-ecosystem: github-actions
|
|
25
|
+
directory: "/"
|
|
26
|
+
schedule:
|
|
27
|
+
interval: weekly
|
|
28
|
+
day: monday
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What does this PR do? One paragraph is enough. -->
|
|
4
|
+
|
|
5
|
+
## Changes
|
|
6
|
+
|
|
7
|
+
<!-- Bullet list of the concrete changes made. -->
|
|
8
|
+
|
|
9
|
+
-
|
|
10
|
+
|
|
11
|
+
## Test plan
|
|
12
|
+
|
|
13
|
+
<!-- How was this tested? Check all that apply. -->
|
|
14
|
+
|
|
15
|
+
- [ ] Added / updated unit tests
|
|
16
|
+
- [ ] All existing tests pass (`pytest tests/`)
|
|
17
|
+
- [ ] Lint and format clean (`ruff check src/ tests/ && ruff format --check src/ tests/`)
|
|
18
|
+
- [ ] Type check passes (`mypy src/`)
|
|
19
|
+
|
|
20
|
+
## Related issues
|
|
21
|
+
|
|
22
|
+
<!-- Fixes #N / Related to #N / N/A -->
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_call:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
name: Test (Python ${{ matrix.python-version }})
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
|
|
24
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
25
|
+
uses: actions/setup-python@v6
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: pip install -e ".[dev,langchain]"
|
|
31
|
+
|
|
32
|
+
- name: Lint
|
|
33
|
+
run: ruff check src/ tests/
|
|
34
|
+
|
|
35
|
+
- name: Format check
|
|
36
|
+
run: ruff format --check src/ tests/
|
|
37
|
+
|
|
38
|
+
- name: Type check
|
|
39
|
+
run: mypy src/
|
|
40
|
+
|
|
41
|
+
- name: Test with coverage
|
|
42
|
+
run: pytest tests/ -v --tb=short --cov=agent_handshake --cov-report=term-missing
|
|
43
|
+
|
|
44
|
+
- name: Verify clean import (no optional deps)
|
|
45
|
+
run: |
|
|
46
|
+
pip install -e "."
|
|
47
|
+
python -c "import agent_handshake; print(agent_handshake.__version__)"
|
|
48
|
+
python -c "from agent_handshake import load_spec, validate_output, FunctionAdapter, SnapshotStore"
|
|
49
|
+
|
|
50
|
+
- name: Verify no unsafe yaml.load
|
|
51
|
+
run: |
|
|
52
|
+
if grep -rn "yaml\.load\b" src/; then
|
|
53
|
+
echo "FAIL: unsafe yaml.load found"
|
|
54
|
+
exit 1
|
|
55
|
+
else
|
|
56
|
+
echo "PASS: only yaml.safe_load used"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
action:
|
|
60
|
+
name: GitHub Action on the example
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/checkout@v6
|
|
64
|
+
|
|
65
|
+
- name: Run the repository action with this commit
|
|
66
|
+
uses: ./
|
|
67
|
+
with:
|
|
68
|
+
package: ${{ github.workspace }}
|
|
69
|
+
working-directory: examples/customer_support
|
|
70
|
+
config: handshake/handshake.yaml
|
|
71
|
+
args: --no-semantic
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
ci:
|
|
9
|
+
uses: ./.github/workflows/ci.yml
|
|
10
|
+
|
|
11
|
+
publish:
|
|
12
|
+
needs: ci
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment: pypi
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write
|
|
17
|
+
contents: read
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v6
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@v6
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
|
|
26
|
+
- name: Install package
|
|
27
|
+
run: pip install -e "."
|
|
28
|
+
|
|
29
|
+
- name: Verify tag matches __version__
|
|
30
|
+
run: |
|
|
31
|
+
TAG="${GITHUB_REF_NAME#v}"
|
|
32
|
+
VER=$(python -c "import agent_handshake; print(agent_handshake.__version__)")
|
|
33
|
+
if [ "$TAG" != "$VER" ]; then
|
|
34
|
+
echo "Tag $TAG != __version__ $VER" && exit 1
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
- name: Build
|
|
38
|
+
run: pip install build && python -m build
|
|
39
|
+
|
|
40
|
+
- name: Publish
|
|
41
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# ========================
|
|
2
|
+
# Python
|
|
3
|
+
# ========================
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[cod]
|
|
6
|
+
*$py.class
|
|
7
|
+
*.so
|
|
8
|
+
*.pyo
|
|
9
|
+
|
|
10
|
+
# Distribution / packaging
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
eggs/
|
|
14
|
+
*.egg
|
|
15
|
+
*.egg-info/
|
|
16
|
+
src/*.egg-info/
|
|
17
|
+
*.whl
|
|
18
|
+
sdist/
|
|
19
|
+
develop-eggs/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
lib/
|
|
22
|
+
lib64/
|
|
23
|
+
parts/
|
|
24
|
+
var/
|
|
25
|
+
MANIFEST
|
|
26
|
+
|
|
27
|
+
# PyInstaller
|
|
28
|
+
*.manifest
|
|
29
|
+
*.spec
|
|
30
|
+
|
|
31
|
+
# Installer logs
|
|
32
|
+
pip-log.txt
|
|
33
|
+
pip-delete-this-directory.txt
|
|
34
|
+
|
|
35
|
+
# ========================
|
|
36
|
+
# Virtual environments
|
|
37
|
+
# ========================
|
|
38
|
+
.venv/
|
|
39
|
+
venv/
|
|
40
|
+
ENV/
|
|
41
|
+
env/
|
|
42
|
+
.python-version
|
|
43
|
+
|
|
44
|
+
# ========================
|
|
45
|
+
# Testing
|
|
46
|
+
# ========================
|
|
47
|
+
.pytest_cache/
|
|
48
|
+
.coverage
|
|
49
|
+
.coverage.*
|
|
50
|
+
htmlcov/
|
|
51
|
+
.tox/
|
|
52
|
+
.nox/
|
|
53
|
+
nosetests.xml
|
|
54
|
+
coverage.xml
|
|
55
|
+
*.cover
|
|
56
|
+
*.py,cover
|
|
57
|
+
.hypothesis/
|
|
58
|
+
|
|
59
|
+
# ========================
|
|
60
|
+
# Type checking & Linting
|
|
61
|
+
# ========================
|
|
62
|
+
.mypy_cache/
|
|
63
|
+
.dmypy.json
|
|
64
|
+
dmypy.json
|
|
65
|
+
.pytype/
|
|
66
|
+
.ruff_cache/
|
|
67
|
+
.pyre/
|
|
68
|
+
|
|
69
|
+
# ========================
|
|
70
|
+
# IDE / Editors
|
|
71
|
+
# ========================
|
|
72
|
+
.vscode/
|
|
73
|
+
!.vscode/settings.json
|
|
74
|
+
!.vscode/tasks.json
|
|
75
|
+
!.vscode/launch.json
|
|
76
|
+
!.vscode/extensions.json
|
|
77
|
+
.idea/
|
|
78
|
+
*.swp
|
|
79
|
+
*.swo
|
|
80
|
+
*~
|
|
81
|
+
.project
|
|
82
|
+
.settings/
|
|
83
|
+
.history/
|
|
84
|
+
*.code-workspace
|
|
85
|
+
*.sublime-project
|
|
86
|
+
*.sublime-workspace
|
|
87
|
+
.spyderproject
|
|
88
|
+
.spyproject
|
|
89
|
+
.ropeproject
|
|
90
|
+
|
|
91
|
+
# ========================
|
|
92
|
+
# OS files
|
|
93
|
+
# ========================
|
|
94
|
+
.DS_Store
|
|
95
|
+
.DS_Store?
|
|
96
|
+
._*
|
|
97
|
+
.Spotlight-V100
|
|
98
|
+
.Trashes
|
|
99
|
+
ehthumbs.db
|
|
100
|
+
Thumbs.db
|
|
101
|
+
Desktop.ini
|
|
102
|
+
*.bak
|
|
103
|
+
*.tmp
|
|
104
|
+
*.log
|
|
105
|
+
|
|
106
|
+
# ========================
|
|
107
|
+
# Environment / Secrets
|
|
108
|
+
# ========================
|
|
109
|
+
.env
|
|
110
|
+
.env.local
|
|
111
|
+
.env.*.local
|
|
112
|
+
*.pem
|
|
113
|
+
*.key
|
|
114
|
+
|
|
115
|
+
# ========================
|
|
116
|
+
# Jupyter Notebooks
|
|
117
|
+
# ========================
|
|
118
|
+
.ipynb_checkpoints/
|
|
119
|
+
*.ipynb_checkpoints
|
|
120
|
+
|
|
121
|
+
# ========================
|
|
122
|
+
# Documentation builds
|
|
123
|
+
# ========================
|
|
124
|
+
site/
|
|
125
|
+
_build/
|
|
126
|
+
docs/_build/
|
|
127
|
+
|
|
128
|
+
# ========================
|
|
129
|
+
# Profiling
|
|
130
|
+
# ========================
|
|
131
|
+
*.prof
|
|
132
|
+
*.lprof
|
|
133
|
+
|
|
134
|
+
# ========================
|
|
135
|
+
# Celery
|
|
136
|
+
# ========================
|
|
137
|
+
celerybeat-schedule
|
|
138
|
+
celerybeat.pid
|
|
139
|
+
|
|
140
|
+
# ========================
|
|
141
|
+
# agent-handshake specific
|
|
142
|
+
# ========================
|
|
143
|
+
|
|
144
|
+
# Generated reports (not committed)
|
|
145
|
+
handshake/reports/
|
|
146
|
+
*.junit.xml
|
|
147
|
+
report.md
|
|
148
|
+
|
|
149
|
+
# NOTE: Snapshots ARE committed to git!
|
|
150
|
+
# They are your test baselines for deterministic replay.
|
|
151
|
+
# Do NOT add handshake/snapshots/ to .gitignore.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.7.0] - 2026-10-16
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- The project is renamed from a2a-spec to agent-handshake. The A2A protocol is
|
|
14
|
+
only one of the agent types it tests, and the old name read as an A2A-only
|
|
15
|
+
tool. New names: package `agent-handshake`, module `agent_handshake`,
|
|
16
|
+
command `handshake`, config file `handshake.yaml`, project folder
|
|
17
|
+
`handshake/`, pytest options `--handshake`, `--handshake-config`,
|
|
18
|
+
`--handshake-no-semantic`, ini option `handshake_config`, fixture
|
|
19
|
+
`handshake_check`, and the GitHub Action `padobrik/agent-handshake`.
|
|
20
|
+
`HandshakeError` and `HandshakeConfig` replace `A2ASpecError` and
|
|
21
|
+
`A2ASpecConfig`. The old names are not kept: the project had no users yet.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- `A2AAdapter` reads file parts. They go under `"files"` in the output: a URL
|
|
25
|
+
file keeps its `url`, a raw file is stored as `size` and `sha256`, and
|
|
26
|
+
`filename` and `mediaType` are kept. Before, a reply with a file part
|
|
27
|
+
raised `AdapterError`.
|
|
28
|
+
|
|
29
|
+
## [0.6.0] - 2026-10-16
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- `a2aspec infer` follows nested reads: `data["customer"]["tier"]`,
|
|
33
|
+
`data.get("customer", {}).get("tier")`, `"tier" in data["customer"]` and
|
|
34
|
+
reads through a local name such as `customer = data["customer"]`. The
|
|
35
|
+
generated spec has nested object schemas with their own `required` lists.
|
|
36
|
+
- `a2aspec infer --check` compares nested reads with the nested schema. A spec
|
|
37
|
+
generated by an earlier version covers only the top-level object, so
|
|
38
|
+
`--check` now reports the nested fields; run `a2aspec infer --force` again.
|
|
39
|
+
- `a2aspec record --agent ID` records only the given agents (repeatable).
|
|
40
|
+
- A scenario can have an `agents` list. `a2aspec record` and
|
|
41
|
+
`a2aspec test --live` then call only those agents with its input. Before,
|
|
42
|
+
every agent in `ADAPTERS` got every scenario.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
- `a2aspec pipeline test` checks policy and semantic rules at each step, not
|
|
46
|
+
only structural rules. It has `--semantic/--no-semantic` like `a2aspec test`.
|
|
47
|
+
Without the `semantic` extra, a pipeline whose specs have semantic rules now
|
|
48
|
+
exits 1 with an install hint; pass `--no-semantic` to skip them.
|
|
49
|
+
|
|
50
|
+
## [0.5.0] - 2026-10-16
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
- A GitHub Action (`uses: padobrik/a2a-spec@v0.5.0`) that installs a2a-spec,
|
|
54
|
+
runs `a2aspec infer --check` and `a2aspec test --format github`. CI runs it
|
|
55
|
+
on the example project.
|
|
56
|
+
- Scenario `expectations` are checked: `a2aspec test` (replay and live) and the
|
|
57
|
+
pytest plugin fail when an agent's output does not have the expected value.
|
|
58
|
+
Before, the field in scenario files was ignored.
|
|
59
|
+
|
|
60
|
+
### Fixed
|
|
61
|
+
- `--format github` annotations use paths relative to the repository root, so
|
|
62
|
+
they attach to the spec file when the project is in a subdirectory.
|
|
63
|
+
- `a2aspec pipeline test --mode live` never loaded `ADAPTERS` and failed on
|
|
64
|
+
the first agent. A failed agent call now fails only its test case, steps
|
|
65
|
+
without a spec show `NO SPEC` instead of `FAIL`, and unknown modes are
|
|
66
|
+
rejected.
|
|
67
|
+
|
|
68
|
+
## [0.4.0] - 2026-10-16
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
- `a2aspec infer --check` compares every inferred spec with its consumer's
|
|
72
|
+
current code and fails when the code reads a field the spec does not cover.
|
|
73
|
+
Inferred specs record their consumer in the new `inferred_from` field, and
|
|
74
|
+
the pytest plugin runs the same check as a `consumer_code` test.
|
|
75
|
+
- `a2aspec test --live` calls each spec's producer through `ADAPTERS` with
|
|
76
|
+
every scenario and checks the live output without saving it. Before, the
|
|
77
|
+
flag only changed the header and still replayed snapshots.
|
|
78
|
+
|
|
79
|
+
### Changed
|
|
80
|
+
- `a2aspec diff` rates a new field as LOW instead of HIGH, so adding a field
|
|
81
|
+
no longer fails CI; a removed field stays HIGH.
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
- `a2aspec record --suite` was ignored; it now records one scenario file.
|
|
85
|
+
- `a2aspec test --format` was ignored. `junit` and `markdown` now print only
|
|
86
|
+
the report on stdout, and the new `github` format adds a GitHub Actions
|
|
87
|
+
annotation for each failure. Unknown formats are rejected.
|
|
88
|
+
|
|
89
|
+
## [0.3.2] - 2026-10-16
|
|
90
|
+
|
|
91
|
+
### Changed
|
|
92
|
+
- README rewritten in Simplified Technical English with a verified Get started
|
|
93
|
+
guide and diagrams; it no longer documents `--format` and `--live`.
|
|
94
|
+
|
|
95
|
+
### Fixed
|
|
96
|
+
- The `a2aspec init` example spec: its PII regexes were double-escaped and
|
|
97
|
+
matched nothing, and its semantic rule lacked `source_field`/`target_field`
|
|
98
|
+
and always failed.
|
|
99
|
+
- `a2aspec init` writes an `ADAPTERS` template and next steps that match the
|
|
100
|
+
current workflow.
|
|
101
|
+
|
|
102
|
+
## [0.3.1] - 2026-10-15
|
|
103
|
+
|
|
104
|
+
### Fixed
|
|
105
|
+
- `a2aspec record` never found project adapters: `a2a_spec/adapters` was
|
|
106
|
+
shadowed by the library's own subpackage. Adapters now load from
|
|
107
|
+
`adapters_dir` (default `./a2a_spec/adapters`) and import errors are reported.
|
|
108
|
+
- The customer support example records and imports correctly from its own
|
|
109
|
+
directory.
|
|
110
|
+
- The `[record]`, `[done]` and `[diff]` labels were swallowed by rich markup.
|
|
111
|
+
|
|
112
|
+
## [0.3.0] - 2026-10-15
|
|
113
|
+
|
|
114
|
+
### Added
|
|
115
|
+
- `A2AAdapter` calls agents that implement the A2A protocol 1.0 through
|
|
116
|
+
their Agent Card and the JSON-RPC binding; the card's version is recorded
|
|
117
|
+
in snapshots.
|
|
118
|
+
|
|
119
|
+
### Changed
|
|
120
|
+
- `Recorder` reads adapter metadata after the call instead of before.
|
|
121
|
+
|
|
122
|
+
## [0.2.0] - 2026-10-15
|
|
123
|
+
|
|
124
|
+
### Added
|
|
125
|
+
- `a2aspec infer` generates a consumer-driven spec from the fields a consumer
|
|
126
|
+
function reads and the producer's recorded snapshots.
|
|
127
|
+
- pytest plugin: with `--a2a` or the `a2a_config` ini option, spec files are
|
|
128
|
+
collected as tests (one per snapshot); the `a2a_check` fixture validates
|
|
129
|
+
live outputs.
|
|
130
|
+
- `a2aspec skill` exports a bundled agent skill for coding agents.
|
|
131
|
+
- `a2aspec diff --base REF` selects the git revision used as baseline.
|
|
132
|
+
- `a2aspec test` evaluates `embedding_similarity` semantic rules against the
|
|
133
|
+
recorded input and output of each snapshot; `--no-semantic` skips them.
|
|
134
|
+
- `LangChainAdapter` is exported from the package root.
|
|
135
|
+
|
|
136
|
+
### Changed
|
|
137
|
+
- **Breaking:** `a2aspec diff` requires snapshots tracked in git; it compares
|
|
138
|
+
against the version at `--base` (default `HEAD`).
|
|
139
|
+
- Semantic rules using `entailment` or `language_detection` now fail with
|
|
140
|
+
"not implemented" instead of being silently ignored.
|
|
141
|
+
- Custom policy validators receive the snapshot input instead of an empty dict.
|
|
142
|
+
- The result header reports FAIL when any layer fails, not only structural.
|
|
143
|
+
- Widened upper bounds for rich, langchain-core, sentence-transformers and dev tools.
|
|
144
|
+
|
|
145
|
+
### Fixed
|
|
146
|
+
- `a2aspec diff` reported no differences after re-recording, because
|
|
147
|
+
recording overwrites the snapshot file; it now compares against the
|
|
148
|
+
committed version and reports new and deleted scenarios.
|
|
149
|
+
- `a2aspec diff` crashed without the `semantic` extra instead of falling back
|
|
150
|
+
to token overlap.
|
|
151
|
+
- `LangChainAdapter` returns `{"content": ...}` for chat messages and uses
|
|
152
|
+
`model_dump()` for pydantic models instead of the deprecated `.dict()`.
|
|
153
|
+
|
|
154
|
+
## [0.1.0] - 2026-02-19
|
|
155
|
+
|
|
156
|
+
### Added
|
|
157
|
+
- Initial public release of a2a-spec.
|
|
158
|
+
- `SnapshotStore` with path-traversal protection.
|
|
159
|
+
- `DiffEngine` for structural and semantic diff of agent outputs.
|
|
160
|
+
- `PipelineExecutor` for DAG-based multi-agent pipeline testing.
|
|
161
|
+
- CLI commands: `record`, `test`, `diff`, `pipeline`, `init`.
|
|
162
|
+
- Frozen dataclasses for `FieldDiff`, `SemanticComparison`, `PolicyResult`.
|
|
163
|
+
- Structured logging via `logging.getLogger(__name__)` in all modules.
|
|
164
|
+
- CI matrix across Python 3.11, 3.12, 3.13.
|
|
165
|
+
- Trusted Publishing workflow for PyPI releases.
|
|
166
|
+
|
|
167
|
+
[0.7.0]: https://github.com/padobrik/agent-handshake/releases/tag/v0.7.0
|
|
168
|
+
[0.6.0]: https://github.com/padobrik/a2a-spec/releases/tag/v0.6.0
|
|
169
|
+
[0.5.0]: https://github.com/padobrik/a2a-spec/releases/tag/v0.5.0
|
|
170
|
+
[0.4.0]: https://github.com/padobrik/a2a-spec/releases/tag/v0.4.0
|
|
171
|
+
[0.3.2]: https://github.com/padobrik/a2a-spec/releases/tag/v0.3.2
|
|
172
|
+
[0.3.1]: https://github.com/padobrik/a2a-spec/releases/tag/v0.3.1
|
|
173
|
+
[0.3.0]: https://github.com/padobrik/a2a-spec/releases/tag/v0.3.0
|
|
174
|
+
[0.2.0]: https://github.com/padobrik/a2a-spec/releases/tag/v0.2.0
|
|
175
|
+
[0.1.0]: https://github.com/padobrik/a2a-spec/releases/tag/v0.1.0
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Contributing to agent-handshake
|
|
2
|
+
|
|
3
|
+
## Development setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
git clone https://github.com/padobrik/agent-handshake.git
|
|
7
|
+
cd agent-handshake
|
|
8
|
+
pip install -e ".[dev]"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
To install optional extras for semantic and LangChain adapters:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install -e ".[dev,semantic,langchain]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Running the checks
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Tests
|
|
21
|
+
pytest tests/
|
|
22
|
+
|
|
23
|
+
# Lint + format
|
|
24
|
+
ruff check src/ tests/
|
|
25
|
+
ruff format src/ tests/
|
|
26
|
+
|
|
27
|
+
# Type check
|
|
28
|
+
mypy src/
|
|
29
|
+
|
|
30
|
+
# All at once
|
|
31
|
+
ruff check src/ tests/ && ruff format --check src/ tests/ && mypy src/ && pytest tests/
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Pre-commit hooks (optional but recommended):
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pre-commit install
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Pull request process
|
|
41
|
+
|
|
42
|
+
1. Fork the repo and create a branch from `main`.
|
|
43
|
+
2. Make your changes with tests covering new behaviour.
|
|
44
|
+
3. Ensure all checks pass locally before pushing.
|
|
45
|
+
4. Open a PR — the CI matrix (Python 3.11 / 3.12 / 3.13) must be green before merge.
|
|
46
|
+
5. Keep PRs focused: one logical change per PR.
|
|
47
|
+
|
|
48
|
+
## Commit style
|
|
49
|
+
|
|
50
|
+
Use the imperative mood in the subject line (`add`, `fix`, `remove`, not `added`).
|
|
51
|
+
Keep the subject under 72 characters. Reference issues with `Fixes #N` in the body.
|
|
52
|
+
|
|
53
|
+
## Reporting bugs
|
|
54
|
+
|
|
55
|
+
Open an issue using the **Bug report** template. Include a minimal reproducible example.
|
|
56
|
+
|
|
57
|
+
## Proposing features
|
|
58
|
+
|
|
59
|
+
Open an issue using the **Feature request** template before starting significant work,
|
|
60
|
+
to avoid building something that won't be merged.
|