Skip to content

Add Bindu A2A integration example (DID-identified agent + optional x402 micropayments)#2

Open
raahulrahl wants to merge 2 commits into
he-yufeng:mainfrom
raahulrahl:feat/bindu-a2a-integration
Open

Add Bindu A2A integration example (DID-identified agent + optional x402 micropayments)#2
raahulrahl wants to merge 2 commits into
he-yufeng:mainfrom
raahulrahl:feat/bindu-a2a-integration

Conversation

@raahulrahl
Copy link
Copy Markdown

Summary

Adds examples/bindu/ showing how to run ContractGuard as a discoverable, DID-identified A2A agent using Bindu. Peers call message/send with either a text part (paste the contract) or a base64 file part (PDF / DOCX / TXT / MD / RTF) and receive the existing AnalysisResult JSON — no schema changes.

The integration is purely additive: nothing under contractguard/ is modified, bindu is not a required dependency, and the CLI / Python API / Gradio UI all keep working unchanged.

This addresses one bullet from the existing Contributing list ("Build integrations — MCP server, VS Code extension, Slack bot, etc."): A2A is the protocol for agent-to-agent calls, so wrapping ContractGuard with bindufy() turns it into a building block that any A2A orchestrator can chain into longer workflows.

What you get when ContractGuard is bindufied

  • Discoverable agent card at /.well-known/agent.json — agent marketplaces and orchestrators can find ContractGuard and know what it does.
  • DID-based identity (did:bindu:…) — each analysis is attributable to a cryptographically-verifiable agent. Result artifacts are signed with the agent's Ed25519 key, so a review can be presented as tamper-evidence ("ContractGuard did:bindu:… said this at timestamp T").
  • A2A JSON-RPC endpoint on port 3773 accepting message/send.
  • Optional pay-per-scan via x402 — uncomment one block in agent.py to charge USDC on Base per analysis. Short path from "open-source CLI" to "monetised hosted service" without a SaaS layer.
  • OAuth2 / mTLS available for B2B deployments.

Files

  • examples/bindu/agent.py — handler wrapping analyze_contract(); handles text parts (with the first short text part treated as a prompt and echoed back) and base64 file parts via the existing contractguard.parser.extract_text path.
  • examples/bindu/README.md — setup, run, curl examples for both inline text and PDF upload, response shape, x402 instructions, limits.
  • examples/bindu/.env.example — minimal config (OPENROUTER_API_KEY), with optional model / language / author overrides.
  • README.md — new "Integrations" section linking to the example.

Test plan

  • python -c "import ast; ast.parse(open('examples/bindu/agent.py').read())" — passes
  • Module imports with bindu installed
  • Handler returns structured {"error": "no_contract", ...} JSON for an empty input
  • _collect_inputs() correctly decodes a base64 file part using examples/sample_lease.txt (returns the full 4,015-char contract and the leading prompt)
  • Live LLM call against OpenRouter — not run here to avoid hitting the maintainer's API quota; the handler delegates to the existing analyze_contract() which already has its own coverage
  • bindufy(config, handler) server startup — recommended manual smoke from the README's instructions

Notes

  • Default model and language are unchanged (anthropic/claude-sonnet-4, en); they can be overridden with CONTRACTGUARD_MODEL and CONTRACTGUARD_LANG.
  • MAX_CONTRACT_CHARS truncation behaviour from analyzer.py is unchanged — long contracts are silently truncated as today.
  • Streaming isn't enabled (Bindu's gRPC streaming path isn't wired up yet for Python handlers); analyses return as a single artifact.
  • examples/bindu/.env.example only documents env vars — no real secrets.

Happy to iterate on style, placement, or naming if you'd prefer it under a different path (e.g. integrations/bindu/).

Run ContractGuard as a discoverable, DID-identified A2A microservice without
touching core analyzer code. Peers send a `text` or base64 `file` part
(PDF/DOCX/TXT/MD/RTF) and get back the existing AnalysisResult JSON. Optional
pay-per-scan via x402 (USDC on Base) — uncomment one block in agent.py.

- examples/bindu/agent.py: handler wrapping analyze_contract()
- examples/bindu/README.md: what/why, setup, curl examples, response shape
- examples/bindu/.env.example: minimal config (OPENROUTER_API_KEY)
- README.md: new Integrations section linking the example

Purely additive: no changes to contractguard/, no new required deps, CLI and
Gradio UI unaffected.
…resp

End-to-end testing against bindu 2026.21.1 revealed three issues in the
first version:

1. Handler walked `parts[]`, but Bindu's manifest worker normalises A2A
   messages to OpenAI-style `{role, content}` before invoking the handler
   (text parts joined with " "). Result: the handler never received any
   contract text and always returned `no_contract`. Rewritten to read
   `m["content"]` directly — drops ~80 lines of dead code.

2. README's curl examples used `"id": "1"` for the JSON-RPC envelope.
   Bindu's pydantic validator rejects non-UUID ids with a 400. Switched
   all examples to proper zero-UUIDs.

3. File-upload path didn't actually work. Bindu's `FileInterceptor` reads
   flat `{kind, mimeType, data}` while the A2A `FilePart` schema (and the
   JSON-RPC validator) expect nested `{kind, file: {bytes, mimeType}}` —
   round-trip is broken in this version. Cut the file section; users
   pre-extract with `contractguard.parser.extract_text()` and send text
   instead.

Also added a complete try-it-out section:
- One-shot bash script that sends `examples/sample_lease.txt`, polls
  `tasks/get`, and prints the DID signature + parsed analysis JSON.
- Sample request body (annotated A2A envelope).
- Sample response — real `tasks/get` output captured by running this
  agent against the sample lease (lease type, F grade, 15/100, with
  trimmed red_flags / warnings / good_clauses / missing_protections).

Verified end-to-end: server starts, agent card resolves with the right
DID, `message/send` is accepted, handler runs, real OpenRouter call
succeeds, result artifact carries a valid Ed25519 signature.
@raahulrahl
Copy link
Copy Markdown
Author

End-to-end tested against bindu==2026.21.1 and pushed a fixup commit. Three real bugs surfaced that the syntax/import checks in the original test plan missed:

  1. Wrong message shape in the handler. Bindu's manifest worker normalises A2A messages to OpenAI-style {role, content} (text parts joined with " ") before invoking the handler. My first version walked parts[] and always hit the no_contract path. Rewritten to read m["content"] directly — drops ~80 lines.
  2. README curl examples failed validation. "id": "1" is rejected by Bindu's pydantic validator with a 400 — JSON-RPC id must be a UUID. Switched all examples to proper UUIDs.
  3. File-upload path didn't actually work. Bindu's FileInterceptor reads flat {kind, mimeType, data} while the A2A FilePart schema (and the JSON-RPC validator) expect nested {kind, file: {bytes, mimeType}} — round-trip is broken in this Bindu version. Cut the file section from the README; users pre-extract with contractguard.parser.extract_text() and send text instead.

Also added a complete try-it-out section with a copy-paste bash script, a sample request body, and a sample response — the response was captured by running this agent against examples/sample_lease.txt: detects type lease, fairness grade F (15/100), 7 red flags, 4 warnings, 2 protections, 7 missing protections. The result artifact carries an Ed25519 did.message.signature, which is the cryptographic-attribution property called out in the description.

Verified working end-to-end:

  • Server start + healthy /health
  • /.well-known/agent.json resolves with a real did:bindu:…
  • message/send accepts the request, handler is invoked
  • Real OpenRouter call succeeds (one analysis on the sample lease)
  • DID signature present on the result artifact

Apologies for shipping the first revision without doing this loop. Happy to keep iterating.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant