Repository navigation
Release: Phase 2 — Differentiate, go beyond (0.2.0) - #1522
Merged
Merged
Conversation
…1143) * chore(deps): refresh the PR CI lock Recompiled by lock-refresh.yml after a green nightly: https://github.com/Donkey-Development-Kit/donkey-development-kit/actions/runs/38558337462 * chore(deps): ship the framework releases in the lock refresh (#1126) The nightly lock refresh moved every pending framework release into the PR CI lock (agent-framework 1.21.0, anthropic 1.13.0, langgraph 1.2.15 with langchain-core 1.6.10 and langchain-openai 1.7.1, strands-agents 1.60.0, google-adk 2.12.0 with litellm 1.105.1, crewai 1.15.28, openai 3.31.0, llama-index-llms-openai 0.8.3). It also moved ruff from 0.16.10 to 0.17.0, but left the ruff-pre-commit rev in .pre-commit-config.yaml at v0.16.10. test_pre_commit_runs_the_lint_jobs_tool_versions pins the two together, so every session that runs the whole suite failed on it. Bump both ruff hooks to v0.17.0. Under ruff 0.17.0 the tree passes ruff check and ruff format --check, and the python/**/*.md code blocks the hook formats are already formatted, so no code changes. Record each framework's offline re-check in docs/verified-apis.md section 8. The live rows keep their 2026-10-13 live dates, because no live round-trip was run. Also: - the LangGraph row now gives use_responses_api=False as the adapter's default (the adapter has defaulted to it since #1043); - the agent-framework middleware row moves to 2026-10-14; - the section 8.1 co-install row notes that agent-framework-anthropic now accepts anthropic 1.x. Closes #1126, #1127, #1128, #1129, #1130, #1132, #1139, #1140, #1141, #1142. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Recompiled python/constraints/ after a green nightly (lock-refresh.yml, ADR 0011), with the docs and llms outputs that restate the lock. Refs #1111
…1165) Ships the nightly lock refresh (#1159) with the ruff pre-commit rev bumped to v0.17.1, and records the offline re-checks in docs/verified-apis.md section 8 (the openai-agents row comes from #1164). Closes #1156 Closes #1157 Closes #1161 Closes #1162 Closes #1163 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1187) ContentSafetyBlocked gains .provider, a stable slug (azure-content-safety, bedrock-guardrails, google-model-armor, crowdstrike-aidr) carried in _CONTENT_SAFETY_VENDORS beside the display name. The refusal span gains donkey.policy.provider and donkey.policy.categories, emitted only for a violation that carries a provider, so a PII or budget refusal omits both. The names are generic so the federated-guardrail types (#313, #1177) reuse them. errors.py and telemetry.py stay at their ratchet ceilings: the growth is offset by reflowing docstrings and comments, with no wording dropped. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Recompiled by lock-refresh.yml after a green nightly: https://github.com/Donkey-Development-Kit/donkey-development-kit/actions/runs/39414748693 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Bumps the github-actions group with 2 updates: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/download-artifact](https://github.com/actions/download-artifact). Updates `actions/upload-artifact` from 7.0.1 to 7.0.2 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](actions/upload-artifact@043fb46...cf430e0) Updates `actions/download-artifact` from 8.0.1 to 8.0.2 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](actions/download-artifact@3e5f45b...9000827) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/download-artifact dependency-version: 8.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the website-npm group in /website with 1 update: [next](https://github.com/vercel/next.js). Updates `next` from 16.3.8 to 16.4.0 - [Release notes](https://github.com/vercel/next.js/releases) - [Commits](vercel/next.js@v16.3.8...v16.4.0) --- updated-dependencies: - dependency-name: next dependency-version: 16.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: website-npm ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* feat(attribution): set the business group per request (#310) One process serving several tenants or teams could only state one business group, fixed on the Donkey's config, so a shared or multi-tenant agent had to build one Donkey per group: a client, pool, auth cache and Budget each (BG §1.7). - donkey.attribution(business_group=, team=, project=, env=, enduser_id=): a dual sync/async scope that attributes every governed call in its block without starting a run. The correlation ID is left alone, so one run can span two cost centres. Its cost tags merge per field over the enclosing binding. - donkey.run(business_group=...) and @donkey.governed(business_group=...) take the same argument when the group belongs to the whole run. - The group rides a contextvar beside the correlation one (core/correlation.py). The transport reads it on every data-plane send and sends it in place of the configured business_group. Precedence: scope, then Donkey config, then env, then file. Control-plane requests never carry it. - The value is validated like a cost tag (cost.validate_tag_value): empty, over-long or control-character values raise ConfigError at the call site. - default_headers snapshot adapters keep the configured group, a documented degradation (BG §1.8). The header name stays the Unverified placeholder (docs/verified-apis.md §3, #21). - Docs: "Per-request attribution" on the telemetry page, and the configuration reference's attribution and header tables. API reference regenerated. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs(website): regenerate llms artifacts for per-request attribution (#310) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(lint): whitelist the public Donkey.attribution for vulture (#310) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| redirect.seen.append({k: self.headers.get(k) for k in ("client_id", "client_secret")}) | ||
| self.rfile.read(int(self.headers.get("content-length") or 0)) | ||
| self.send_response(307) | ||
| self.send_header("location", f"{target_origin}{self.path}") |
| def do_POST(self) -> None: | ||
| self.rfile.read(int(self.headers.get("content-length") or 0)) | ||
| self.send_response(307) | ||
| self.send_header("location", f"{target}{self.path}") |
tommasobolis
marked this pull request as draft
October 30, 2026 15:09
Collaborator
Author
|
Held as draft: this is the develop → main promotion. It merges only with the maintainer's explicit approval, as a no-ff merge commit ( |
tommasobolis
marked this pull request as ready for review
October 30, 2026 15:16
This was referenced Oct 30, 2026
amirkhan-ak-sf
had a problem deploying
to
github-pages
October 30, 2026 22:28 — with
GitHub Actions
Failure
This branch had an error being deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promotion of
develop→mainfor 0.2.0.developreads__version__ = "0.2.0"(#1521), andmainis on 0.1.3.Included
Everything on
developsince the 0.1.3 promotion (#1138): Phase 2 (epic #260) and the 0.2.0 pre-release code review (epic #1414). The release readiness work is tracked in #1435. Per-PR list: main...developStill open in the milestone, and closed after the tag: #1435, #1414, #260, and #219 (its demos PR pins the published package).
Breaking changes
From 0.1.3. No name was removed from
donkey_kit, and no extra was dropped. These changes can still affect existing code. Each has its own section, with the fix, in MIGRATION.md.401is nowGatewayApprovalPending, whichexcept AuthError:no longer catches, and a CIBA denial403isGatewayApprovalDenied(classify: type the OBO policy's CIBA authorization_pending instead of AuthError #1320). Google Model Armor and CrowdStrike AIDR blocks areContentSafetyBlockedinstead ofPolicyViolation(policy="unknown"), and theirdonkey.policy.typereadscontent_safety(refusals: type the Google Model Armor Guardrails rejection #1178, refusals: type the CrowdStrike AIDR Guardrails rejection #1176).classifyis aClassifierobject. Calling it works as before, butinspect.isfunction(classify)isFalse. To type a custom policy, useclassify.register()instead of wrapping it (feat(classify): registry so custom gateway policies become typed exceptions #1152).NotImplementedErrornow run.donkey publishanddonkey verifyare visible and do the work: they exit 0, 1 or 2, and no longer exit 3 (scanner: donkey publish registers the manifest with Exchange / Agent Registry #218, cli: wire donkey verify to Publication.verify() #1352).discover(),donkey.registry.search(),resolve_mcp()/resolve_agent(),explain(),Publication.verify(), theToolSetbindings andderive_descriptor(mode="auto…")make control-plane calls. Anexcept NotImplementedError:fallback around them is no longer reached. A gateway credential is held back from abase_urlset in the project files that isn't a regional Anypoint host (ADR 0019, tools: apply the ADR 0005 endpoint check to the gateway credential on discovered servers #1479).donkey.tools.discover()defaults togoverned=True. Passgoverned=Nonefor the unfiltered list (ADR 0017, tools: confirm or revisit discover()'s unfiltered default before 0.2.0 #1424).GovernanceCriteriais imported fromdonkey_kitagain.from donkey_kit.experimental import GovernanceCriteriastill works, but it emits aDeprecationWarning(release: settle the stability tier of the new 0.2.0 public surface #1425).[cli]needstyper>=0.26.0andrich>=13.8.0, and no longer installsclick(Nightly framework matrix failing #1196).[all]addsmcpanda2a, and[adk]installslitellm[mcp](see Extras changes).AgentKilledis terminal for theDonkeythat saw it. Build a newDonkeyto carry on (killswitch: recognise the kill-switch rejection and stop cleanly #220).refusal_translatorleaves the__all__of the Agent Framework and Strands adapters. A direct import still works (adapters: drop internal hooks from __all__ and unify the approval helpers #1422).ConfigErrorbefore anything is sent. Before, httpx sent those credentials to the host asAuthorization: Basic(core: refuse a user name or password in configured endpoint URLs #1478).AgentFrameworkAdapter(...).policy_middleware()withoutagent_frameworkinstalled raises the install-hintImportErrorinstead ofNotImplementedError(agent_framework: policy_middleware() raises NotImplementedError instead of the install hint when agent_framework is missing #1503).From a 0.2.0 pre-release (
0.2.0.devN,0.2.0rc1). These surfaces first shipped in the 0.2.0 pre-releases, and they changed before the final with no deprecation cycle. The full list is in MIGRATION.md. The changes most likely to need a code edit:donkey.as_user(id_token=...)isdonkey.as_user(token=...), andtoken_exchange_pathis gone.as_user()refuses anllm_proxy_urlfrom the working-directory config files. Set it in the environment or in code, or setDONKEY_TRUST_PROJECT_CONFIG=1.ToolSet.openai()isToolSet.openai_agents(). A per-tool binding raisesAuthErrorunder a differentas_user()user, so bind inside the block that runs the agent. A gateway with a plainhttp://public URL is refused unlessDONKEY_ALLOW_HTTP=1is set.donkey.approvalsis per client, and the module-level instance is gone (ADR 0018). An unknown approval id raisesApprovalNotFound, which is still aKeyError.ApprovalRejectedandGatewayApprovalDeniedshare the newApprovalErrorbase. A resumed approval runs as its requester. The adapter helpers returnApprovalobjects, with the framework object on.native. A Strands approval covers exactly one call.require_approval()on a whole-server binding raisesConfigError.donkey dev --versionis--agent-version. The--jsondocuments carry their own format key (publish_format,verify_format,expose_format). A failedpublish --jsonprints its outcome and exits 1.donkey verifyexits 2 with no gateway credential. Pass the Action'sclient-secretfromsecrets.*; itsskippedoutput is gone.ImportErrorinstead of a bareModuleNotFoundError.Notes
donkey-kit 0.2.0: Phase 2, Differentiate, go beyond. This release adds the capabilities a stock OpenAI client with a
base_urlcan't offer, because they depend on the platform behind the gateway. You get governed MCP tool access, publication to Exchange from your code and CI, on-behalf-of user identity, and human-in-the-loop approvals, including the gateway's own CIBA step-up. You also get an A2A server built on the officiala2a-sdk, declarative refusal handlers, typed custom policies, and the OpenAI Agents SDK as the second deep adapter.Highlights
donkey.tools.discover()finds governed MCP servers in Exchange.ToolSetbinds them to LangGraph, the OpenAI Agents SDK, ADK, Strands, MS Agent Framework, Anthropic, CrewAI and LlamaIndex through the governed gateway (tools: donkey.tools.discover() returns governed MCP tools as native framework tools #221, feat(tools): donkey.tools.discover() and the ToolSet framework bindings (#221) #1308, feat(tools): bind discovered MCP servers through the live gateway, CrewAI binding (#221) #1310). A server that isn't governed is refused withUngovernedMcpServer(feat(tools): refuse to bind MCP servers that are not governed (#1150) #1199), and the gateway's tool-access denial is typed asToolNotInProfile(feat(tools): type the gateway's MCP tool-access denial as ToolNotInProfile #1362).donkey.tools.warm()pre-fills the discovery cache (feat(tools): add donkey.tools.warm() to pre-fill the discovery cache #1333), and discovery emits a span with cache hit and miss counters (feat(tools): a discover() span with cache hit/miss counters #1351).donkey scanderives a deterministic model of your agents, tools and MCP servers (feat(scan): donkey scan derives a deterministic model of agents, tools and MCP servers (#217) #1192).donkey publishregisters MCP servers and agents in Exchange with a full asset page, including a "Changes since" section (feat(cli): donkey publish registers MCP servers in Exchange (#218) #1259, feat(registry): publish MCP metadata and an Exchange page (#1269) #1270, feat(registry): Overview section and tool governance on the Exchange page (#1273) #1277, feat(publish): publish agent assets and unhide donkey publish #1291, feat(publish): the Exchange page lists what changed since the previous version (#1271) #1358).donkey verifychecks what you published against the live tools and agent card (feat(cli): donkey verify checks published MCP servers against their live tools (#1352) #1355, feat(registry): verify an A2A agent's published card against its live card (#1354) #1361). The scan-and-publish GitHub Action runs this from CI (feat: the scan-and-publish GitHub Action, and donkey publish --json (#219) #1263).donkey.as_user(token=...)forwards the user's token to the gateway's OBO policy on model calls and MCP bindings. It never falls back to the service identity (feat(identity): donkey.as_user() on-behalf-of token exchange #1290, feat(identity): as_user() fails hard, never as the service identity #1293, feat(identity): as_user() forwards the user token, no SDK exchange (BG §2.4) #1353, feat(identity): carry the donkey.as_user() token on MCP ToolSet bindings (BG §2.4) #1369, feat(identity): give UserScope a sync with, and include mcp in [all] #1472).@donkey.tool(approval="required")andToolSet.require_approval()pause gated tools with each framework's own mechanism: LangGraphinterrupt(), OpenAI Agentsneeds_approval, ADK tool confirmation and Strands interrupts (feat(hitl): approval-gated tools with @donkey.tool(approval="required") (BG §2.3) #1154, feat(hitl): LangGraph interrupt() and Command(resume=) for approval-gated tools (BG §2.3) #1155, feat(tools): ToolSet.require_approval() gates discovered MCP tools (#1153) #1201, feat(openai_agents): map tool approvals onto needs_approval (BG §2.3) #1233, feat(strands): pause approval-gated tools with Strands' own interrupt (BG §2.3) #1239, feat(adk): pause approval-gated tools with ADK's own tool confirmation (BG §2.3) #1241). The gateway's CIBA step-up arrives as typed, waitableGatewayApprovalPending/GatewayApprovalDenied(feat(core): type the OBO policy's CIBA step-up answers (#1320) #1329, Carry gateway CIBA step-up as typed, waitable approvals #1376).donkey.serve()wraps the officiala2a-sdk, with a governed inbound (feat(a2a): donkey.serve() wraps the official a2a-sdk #1212, feat(a2a): governed inbound for donkey.serve() tasks (#225) #1225).donkey devruns a simulated A2A ingress, anddonkey expose/donkey preflightput the gateway instance in front of your agent (feat(a2a): donkey dev with a simulated A2A ingress (BG §2.9.3) #1287, feat(cli): donkey expose and donkey preflight #1330).donkey.on(...)) react but never un-refuse (feat(refusals): declarative refusal handlers that react but never un-refuse (BG §2.1) #1146). A classification registry turns custom gateway policies into typed exceptions (feat(classify): registry so custom gateway policies become typed exceptions #1152). The kill switch stops runs cleanly (feat(killswitch): stop cleanly on the Agent Kill Switch (BG §2.6) #1151), and Google Model Armor and CrowdStrike AIDR blocks are typed asContentSafetyBlocked(feat(refusals): type the Google Model Armor Guardrails rejection (#1178) #1180, fix(refusals): type CrowdStrike AIDR from its policy source (ADR 0016) (#1429) #1461).donkey.run()keeps a run ledger (feat(telemetry): run ledger for donkey.run() (#613) #1379). You can set the business group per request (feat(attribution): set the business group per request (#310) #1190) and send a provider key for Dynamic-key routes (feat(config): send the provider key in a configurable header for Dynamic-key routes (BG §1.1) #1253). The budget has a stated concurrency contract (fix(budget): state and enforce the concurrency contract for Budget and correlation (#311) #1189) and reads the upstream provider's rate-limit window (feat(budget): read the upstream provider's rate-limit window as its own source (BG §1.3) #1246).donkey dev,serve()and scanned endpoints are hardened for non-loopback use (Harden donkey dev, serve() and scanned endpoints for non-loopback use #1458).send()(fix(budget): ignore an out-of-range reset header instead of crashing send() #1456).Extras changes (§8.4)
mcpis back (mcp>=1.24) forToolSetbinding. It was dropped in 0.1.2 and last shipped asmcp>=1.2.a2ais back (a2a-sdk[http-server]>=1.2.0,uvicorn>=0.30) fordonkey.serve(). It was dropped in 0.1.2 and last shipped asa2a-sdk>=0.1.allnow installsllm, langgraph, otel, cli, local, a2a, mcp, so it addsmcpanda2a(identity: give UserScope a sync with, and include mcp in [all] #1436).adk:litellm>=1.84becomeslitellm[mcp]>=1.84. From litellm 1.106,model()with tools needsmcp(fix(adk): install litellm's mcp extra so tool-bearing model() runs work (#1267) #1289).cli:typer>=0.15.4becomestyper>=0.26.0, andrich>=13.0becomesrich>=13.8.0(fix(cli): raise the typer floor to 0.26.0 so argument help survives click 8.5 #1200).donkeyconsole script and the pytest plugin entry point are unchanged. Extras stay floors only, with no upper pins.Verification-status changes (§0.3)
In
docs/verified-apis.md:ToolSetbinding through the governed gateway move from blocked to VERIFIED (LIVE), 2026-10-28 (§9, tools: donkey.tools.discover() returns governed MCP tools as native framework tools #221). They run over framework binding classes that are VERIFIED (local round-trip) (verify(adk): installed constructor, MCP binding and descriptor APIs (§§8–10) #636–verify(agent-framework): MCP binding and descriptor APIs (§§9–10) #652). The tool-access denial shape is VERIFIED (LIVE) (docs(verified-apis): live-verify the MCP tool-access denial shape (BG §2.7) #1359).explain()are VERIFIED (LIVE) (§6, verify: resolve an Exchange MCP asset to its governed gateway endpoint #1297, verify: read an MCP instance's governed state so registry.explain() reports real checks #1298, verify: read back a published A2A agent's card and its live card through the gateway #1354).donkey verify. The read-back of a published version's MCP tools and agent card, whichdonkey verifycompares against, is VERIFIED (LIVE), 2026-10-29 (§7, test(conformance): restore the 13 retired scenarios once their surfaces are verified #991, verify: read back a published A2A agent's card and its live card through the gateway #1354).as_user()header. The user-token header is VERIFIED (LIVE), 2026-10-29:Authorization: Bearer <token>, on model calls and MCP bindings (§13, verify: the Trusted Agent Identity token-exchange endpoint and header #255).401), denied (403) and initiation-failure (502) shapes are VERIFIED (LIVE), 2026-10-28 and 2026-10-29, on model and MCPtools/calltraffic (§4, classify: type the OBO policy's CIBA authorization_pending instead of AuthError #1320, Flip CIBA tools/call and 502 rows to VERIFIED (LIVE) in verified-apis.md #1380).crowdstrike-aidr-guardrails-policy1.0.0, not captured live, because no proxy runs it.classify()types it asContentSafetyBlocked(provider="crowdstrike-aidr"). The live capture is still open (verify: capture the CrowdStrike AIDR Guardrails rejection live #1184), and a capture replaces the derived shape if they differ (§4, refusals: type the CrowdStrike AIDR Guardrails rejection #1176, refusals: stop typing CrowdStrike AIDR until its shape is captured live #1429).NotImplementedError("blocked on verification: …"):donkey.tools.lock(),discover(locked=True));search(governed=, environment=, domain=));Publication.preview()/export();donkey status.Acceptance
donkey-kit==0.2.0from TestPyPI: passed. This was a live run of all seven groups (./run.sh --version 0.2.0 --index testpypi) on Python 3.12, against the artifact this Release publishes.[all]+langchain-mcp-adapters(data plane, governance, public surface, blocked, telemetry, frameworks)[all,adk][all,strands][all,agent_framework][all,openai-agents][all,anthropic][all,crewai]+crewai-tools[mcp][all,llamaindex]+llama-index-tools-mcp0.2.0rc1also passed the live run (546 passed, 33 skipped, 0 failed).