SDK parity
Three SDKs, deliberately not identical. The gaps are listed so you find them here rather than three files into an integration.
The matrix
Section titled “The matrix”| Go | Python | TypeScript | |
|---|---|---|---|
| Typed verbs | ✅ | ✅ | ✅ |
| Governance interpretation | ✅ | ✅ | ✅ |
Retries + Retry-After | ✅ | ✅ | ✅ |
| Typed errors | ✅ | ✅ | ✅ |
| Idempotent writes | ✅ | ✅ | ✅ |
| Environment facade | FromEnv() | from_env() | ❌ |
| Auth / credential exchange | ✅ | ✅ | ❌ |
| Context meter | ✅ | ✅ | ❌ callTool |
| Testing fake | vectadynetest | FakeControlPlane | ❌ |
| Async | goroutines | AsyncVectadyne | native |
| Compile-time request validation | partial | partial | ✅ best |
Nothing in the ❌ column is a missing capability — everything is reachable through callTool with
the same validated shapes. What is missing is convenience.
Which to pick
Section titled “Which to pick”| Go | The most complete. Pick it for production agents, especially unattended ones — it has auth, a meter and a testing fake |
| Python | Complete, and where most framework integrations live (LangChain, LangGraph). Sync and async facades at parity |
| TypeScript | Best compile-time safety. Pick it for browser or Node agents, and expect to write the auth and telemetry wiring |
The polarity difference
Section titled “The polarity difference”This is the one thing that will bite you, so it is not buried in a footnote:
| SDK | Field | true means |
|---|---|---|
| Go | Guidance.Hold | stop |
| TypeScript | guidance.hold | stop |
| Python | GovernanceDecision.proceed | go |
Never port a branch between languages by eye. See Interpret a verdict.
What all three guarantee
Section titled “What all three guarantee”These are contract, not implementation detail — every SDK proves each with a test:
- A
warnproceeds. Never a hold. - An unknown decision holds. Fail-closed on a vocabulary the client cannot interpret.
- A refusal is never retried. A
block, awarnand aforbiddenfault each produce exactly one request. - No synthesized verdict. An unreachable control plane is a typed transport error, never an
invented
allow. Retry-Afteris honoured, and surfaces typed when retries are exhausted.- A write freezes its payload. Serialized once per logical call and replayed byte-identically, so a retry cannot append a duplicate.
- Credentials are structurally redacted. Every formatting path yields
<redacted>; reading the value is explicit and greppable. - Nothing sensitive is logged. Not tokens, secrets,
prompt_block, memory content or evidence summaries — enforced by the log hook’s signature, which cannot see a body.
No framework adapters
Section titled “No framework adapters”None of them ship framework glue. It would force that framework into the build of every consumer who does not use it, and it rots on the framework’s release schedule rather than ours.
The glue lives in your agent and is short. See LangChain and ADK (Go).
No OpenTelemetry dependency
Section titled “No OpenTelemetry dependency”Same reasoning. Propagation is a seam: supply an HTTP client whose transport injects
traceparent — exactly what otelhttp.NewTransport does — and the SDK carries whatever headers it
sets.
If you emit spans, a governance refusal is a span EVENT, never a span ERROR, and the span status
stays OK. Marking warn as an error teaches every dashboard that governance is a failure mode.
Use two levels: an attempt span may be Error on a transport failure; the logical call is
OK if any attempt succeeded. One level either paints a recovered call red or an exhausted one
green.
Packages
Section titled “Packages”| Go | go.vectadyne.ai/vectadyne — pkg.go.dev |
| Python | vectadyne-agent (imports as vectadyne) — PyPI |
| TypeScript | @vectadyne/sdk — npm |
- Go · Python · TypeScript