Skip to content

fix(a2a): resolve a role's environment to a provisioned id (FA-14) - #146

Merged
izzywdev merged 3 commits into
mainfrom
feat/a2a-resolve-role-environment-fa14
Aug 4, 2026
Merged

fix(a2a): resolve a role's environment to a provisioned id (FA-14)#146
izzywdev merged 3 commits into
mainfrom
feat/a2a-resolve-role-environment-fa14

Conversation

@claude

@claude claude Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • A2AAdapter._provision always produced environment_id: null for A2A-provisioned sessions: ensure_agent() (anthropic provider) never returns one, and no tenant sets provider.environmentId. This fixes the A2A provisioning path to resolve role["environment"] to a real provider environment id.
  • Added agent-templates/a2a/environments.py (EnvironmentResolver), which mirrors providers/provision.py's existing basename -> name -> id lookup exactly (_env_basename_to_name + env_ids.get(...)), instead of inventing a new scheme. It reads environments/<basename>.json for the name, and ${FUZE_STATE_DIR:-/state}/environment-ids.json (the {name: id} map batch provisioning writes) for the id — both cached for the resolver's lifetime, never re-read per call.
  • Wired the resolver into A2AAdapter.__init__ as an injectable environment_resolver callable (default: a real EnvironmentResolver()), so _provision never reads global state itself — it only calls the resolver.
  • Precedence in _resolve_environment_id:
    1. tenant.provider.environment_id (values provider.environmentId) — explicit per-tenant override, wins outright.
    2. Else, if the role names an environment, resolve it via EnvironmentResolver. Raises EnvironmentResolutionError (never silently falls back to null) if the basename has no matching environments/*.json, that file has no name, or the name has no provisioned id yet.
    3. Else (the role names no environment at all) — legitimately None, not an error; falls back to whatever ensure_agent()'s response carried, if anything.
  • Added agent-templates/environments/cloud-orchestrator.json (this repo didn't have an environments/ dir yet) and bound it to the served agent-orchestrator role (environment: cloud-orchestrator), so this fix has a real environment to resolve against in this repo's own dispatch path, not only in tests.

Design note for reviewers

A role's environment is documented (role-manifest.schema.json) as a basename of a file in the same repo's agent-templates/environments/. Since each onboarded repo runs its own providers/provision.py against its own environments, and the A2A server's FUZE_STATE_DIR/environment-ids.json is a single shared mount (a2a-shared chart's deploy.stateConfigMap: a2a-state) across however many tenants it serves, I resolved basenames against this repo's own agent-templates/environments/ (sibling to a2a/, exactly mirroring provision.py's ENV_DIR construction) rather than each tenant's checked-out repo. This keeps the fix a literal mirror of the existing provisioning pattern per the ticket's guardrail ("do not invent a new scheme") and doesn't touch loader.py's tenant-repo resolution. If the intent is instead per-tenant environment definitions, that's a bigger design question (how a single shared id-state file disambiguates environment names across repos) worth a follow-up ticket rather than folding into FA-14.

Type of change

  • Bug fix

Checklist

  • Branch named feat/…
  • Conventional commit messages
  • Commits are signed (verified)
  • Tests added/updated where relevant
  • Harden Gate checks pass (lint, test, build, sast, secret-scan, dependency-scan) — pending CI run
  • Conversations resolved and ready for code-owner review

Test plan

  • cd agent-templates/a2a && python3 -m pytest -q --ignore=tests/test_server.py -> 126 passed, 2 failed (the 2 failures are pre-existing schema drift in test_role_manifest_schema.py, unrelated to this change — confirmed identical failure count/names on main before this branch's changes).
  • New tests in agent-templates/a2a/tests/test_environments.py (11 tests, all passing): EnvironmentResolver basename->id resolution, caching (deletes backing files after first call, resolver still returns the cached id), unknown-basename error, name-with-no-provisioned-id error, missing-state-dir-still-errors-for-a-named-env; adapter-level precedence (tenant override wins, resolved role environment, no-environment role -> None, unresolvable named environment raises); and an end-to-end send_message test asserting create_session receives the resolved id, never None.
  • tests/test_server.py fails to collect (httpx2 missing) both before and after this change — known/excluded per the ticket, not addressed here.

Related issues

Jira FA-14 (epic FA-2)


Generated by Claude Code

_provision() previously left environment_id null for every A2A-provisioned
session: ensure_agent() never returns one, and no tenant sets
provider.environmentId. Add EnvironmentResolver (a2a/environments.py),
mirroring providers/provision.py's basename->name->id lookup exactly, and
wire it into A2AAdapter.__init__ (cached for the adapter's lifetime, never
re-read per call). Precedence: tenant.provider.environment_id overrides
everything; else a role naming an environment resolves through
EnvironmentResolver, which raises rather than silently returning null when
the name can't be resolved; a role naming no environment legitimately
resolves to None.

Adds agent-templates/environments/ (cloud-orchestrator.json) and binds it
to the served agent-orchestrator role so the fix has a real environment to
resolve against in this repo, not just in tests.

Jira: FA-14 (epic FA-2)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@claude
claude Bot requested a review from izzywdev as a code owner August 4, 2026 08:01
@izzywdev
izzywdev merged commit 0deec71 into main Aug 4, 2026
33 checks passed
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.

2 participants