Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 50 additions & 7 deletions .agents/skills/a2a-protocol/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@ fixing it. If A2A delegation is unreliable, fix A2A — file it as a bug in the
delegation path (timeout handling, retries, typed terminal states), don't
route around it app by app.

Connecting app A to app B is two independent things, and both must be true:
Connecting app A to an Agent-Native app B is two independent things, and both
must be true:

1. **B is registered on A** as a `remote-agents/<id>.json` resource.
2. **A and B share a secret**, so A's signed JWT verifies on B.

Neither is a code change, and neither is symmetric. Registering B on A does not
let B call A.
let B call A. A hosted peer uses provider-specific endpoint and credential
metadata in place of the shared Agent-Native secret, but it still does not make
the provider's model or SDK an A2A endpoint.

## A2A is already mounted

Expand Down Expand Up @@ -62,13 +65,30 @@ A remote agent is **a row in the resources table, not a file on disk**. Path
"name": "Analytics",
"description": "Queries analytics data across providers",
"url": "https://analytics.example.com",
"color": "#6B7280"
"color": "#6B7280",
"cardUrl": "https://analytics.example.com/.well-known/agent-card.json",
"auth": {
"type": "bearer",
"credentialRef": "ANALYTICS_A2A_TOKEN"
}
}
```

`url` is the only required field. `parseRemoteAgentManifest` accepts **only**
these five keys — there is no `apiKey`, `env`, `skills`, or `token` field, and
anything else is silently dropped.
`url` is the only required endpoint field. `cardUrl` is the optional discovery
URL for providers that do not serve `/.well-known/agent-card.json`. The client
reads the protocol version from the agent card. Pass `protocolVersion` directly
to `A2AClient` when a provider's card omits it. The optional `auth` descriptor is
non-secret connection metadata. Use
`{ "type": "bearer", "credentialRef": "..." }` for a vault-backed bearer
credential, or `{ "type": "oauth-client-credentials", "tokenUrl": "...",
"clientId": "...", "clientSecretRef": "...", "scope": "..." }` when the
peer issues OAuth client-credentials tokens. `credentialRef` and
`clientSecretRef` are references, never secret values.

Do not add `apiKey`, `env`, `skills`, or `token` values to a manifest. Resolve
credentials server-side from the workspace connection or vault. A direct
`A2AClient` call can pass `cardUrl` and `protocolVersion` while a provider
adapter is being used, but browser code must never receive the credential.

Four ways to create it, all writing the same row:

Expand Down Expand Up @@ -139,7 +159,30 @@ request is genuine loopback or `A2A_ALLOW_UNSIGNED_INTERNAL=1`.
`A2AConfig.apiKeyEnv` still exists for static bearer auth against non-agent-native
peers, but the framework's own mount never sets it. Do not reach for it when
debugging a connection between two agent-native apps — the answer there is
always the shared secret.
always the shared secret. For a provider that uses OAuth, resolve and refresh
the access token in a server-side adapter. `A2A_SECRET` is not a substitute for
the provider's Entra, Google, or other OAuth credential.

## Hosted providers

Foundry, Gemini Enterprise, and other hosted services can be A2A peers only
when they expose a compatible protocol endpoint. Foundry hosted agents run
agent code in managed containers and can expose A2A through Agent Service. Keep
the Agent-Native UI, actions, and PostgreSQL app on its normal host. Foundry
callers use Microsoft Entra bearer tokens with Foundry Agent Consumer access,
so configure `cardUrl` and obtain the token through the workspace credential
provider. Pass `protocolVersion` to `A2AClient` only when the card omits it. See
the [Foundry hosted agent overview](https://learn.microsoft.com/en-us/azure/foundry/agents/overview)
and [A2A endpoint guidance](https://learn.microsoft.com/en-us/azure/foundry/agents/how-to/enable-agent-to-agent-endpoint).

Gemini Enterprise can register external A2A agents. Its Agent Registry
HTTP+JSON proxy uses `{url}/v1/card`, `{url}/v1/message:send`, and
`{url}/v1/message:stream` with Google OAuth or ADC bearer credentials. These
paths are different from this skill's JSON-RPC paths, so use a server-side
adapter that translates the request and refreshes Google credentials. If a
provider exposes standard A2A JSON-RPC separately, use the generic bearer
path. A model provider or SDK without an A2A endpoint needs such an adapter
before an Agent-Native app can call it.

Never hardcode either secret in source, docs, prompts, app state, action
descriptions, client bundles, or examples. Read them from runtime config; never
Expand Down
5 changes: 5 additions & 0 deletions .changeset/hosted-a2a-peer-connections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@agent-native/core": minor
---

Document hosted A2A peer connection metadata and provider-specific authentication guidance for Foundry and Gemini Enterprise.
102 changes: 102 additions & 0 deletions packages/core/docs/content/a2a-protocol.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,108 @@ const response = await callAgent(
console.log(response); // "There were 1,247 signups last week..."
```

## Hosted-agent connections {#hosted-agent-connections}

A hosted agent can participate in A2A when it exposes an A2A endpoint. A model
provider or agent SDK alone is not an A2A peer. Keep the app's UI, actions, and
database on your normal app host, then connect the agent runtime through an
adapter or its A2A endpoint.

A hosted connection has endpoint metadata and an auth descriptor. Keep this
metadata with the remote-agent resource or connection record. Never put a token
or client secret in the manifest:

```json
{
"id": "foundry-research",
"name": "Foundry Research",
"url": "https://example.services.ai.azure.com/a2a",
"cardUrl": "https://example.services.ai.azure.com/agentCard/v0.3",
"auth": {
"type": "bearer",
"credentialRef": "FOUNDRY_A2A_TOKEN"
}
}
```

`url` is the invocation endpoint or base URL. `cardUrl` is optional when
discovery uses `/.well-known/agent-card.json`. Use it when the provider
publishes its card elsewhere. The client reads the protocol version from the
agent card. When a provider's card omits it, pass `protocolVersion` directly to
`A2AClient`. `auth` names how server-side code obtains a bearer token. Supported
descriptors are `bearer` with a vault-backed
`credentialRef`, or `oauth-client-credentials` with `tokenUrl`, `clientId`,
`clientSecretRef`, and `scope`. `credentialRef` and `clientSecretRef` refer to
secrets, not secret values.

### Generic bearer A2A {#generic-bearer-a2a}

Use the standard client when the peer accepts `Authorization: Bearer ...`,
serves a compatible card, and accepts Agent-Native JSON-RPC:

```ts
const client = new A2AClient(endpoint, token, {
cardUrl,
protocolVersion: "0.3",
});
```

Resolve `token` server-side from the workspace connection or vault. Do not
send it from browser code, write it to a manifest, or include it in a prompt.
A static API key is only a transport credential for the remote service. It does
not establish Agent-Native caller identity or carry `approvedActions`.

### Microsoft Foundry {#microsoft-foundry}

[Azure AI Foundry hosted agents](https://learn.microsoft.com/en-us/azure/foundry/agents/overview)
run your agent code or container behind a managed endpoint, identity, scaling,
session state, and observability. This hosting model is for the agent runtime.
Keep your Agent-Native UI, actions, and PostgreSQL deployment on the app host
and call the Foundry endpoint from server-side code.

Foundry can expose an A2A endpoint through [Agent Service](https://learn.microsoft.com/en-us/azure/foundry/agents/how-to/enable-agent-to-agent-endpoint).
It requires Microsoft Entra authentication, and the caller needs Foundry Agent
Consumer permission. Use the provider's v0.3 card and endpoint with `cardUrl`
when that endpoint speaks Agent-Native JSON-RPC. Pass `protocolVersion` to
`A2AClient` only when the card omits it. The token provider must obtain and
refresh an Entra access token. `A2A_SECRET` and a static API key do not satisfy
Foundry authentication.

For service-principal client credentials, request the Entra scope
`https://ai.azure.com/.default` and grant the caller the **Foundry Agent
Consumer** role at the project or agent scope. Store the client secret in the
vault and reference it from the manifest:

```json
{
"auth": {
"type": "oauth-client-credentials",
"tokenUrl": "https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token",
"clientId": "<application-id>",
"clientSecretRef": "FOUNDRY_CLIENT_SECRET",
"scope": "https://ai.azure.com/.default"
}
}
```

### Gemini Enterprise {#gemini-enterprise}

[Gemini Enterprise can register external A2A agents](https://docs.cloud.google.com/gemini/enterprise/docs/register-and-manage-an-a2a-agent),
and its Agent Registry can publish a proxy endpoint. Its HTTP+JSON binding is
provider-specific: discovery uses `GET {url}/v1/card`, invocation uses
`POST {url}/v1/message:send`, and streaming uses `POST {url}/v1/message:stream`.
Requests use Google OAuth or ADC bearer tokens and Google Cloud IAM. See
[Call an agent using its registry A2A endpoint](https://docs.cloud.google.com/gemini/enterprise/docs/invoke-agent-a2a)
for the endpoint and permission requirements.

Those paths are different from the Agent-Native JSON-RPC paths
(`/.well-known/agent-card.json` and `/_agent-native/a2a`). Register the
endpoint only after an adapter translates the wire format and obtains and
refreshes Google credentials. If the target exposes a standard A2A endpoint
separately, use that endpoint with the generic bearer guidance. Gemini
Enterprise registration traffic does not go through Agent Gateway policies, so
apply the target's own auth and authorization policy.

## Programmatic workspace invoke {#programmatic-invoke}

For agent-native workspaces, prefer the `agentNative` helper when code or a
Expand Down
97 changes: 97 additions & 0 deletions packages/core/docs/content/locales/ar-SA/a2a-protocol.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,103 @@ const response = await callAgent(
console.log(response); // "There were 1,247 signups last week..."
```

## اتصالات الوكلاء المستضافة {#hosted-agent-connections}

يمكن للوكيل المستضاف المشاركة في A2A عندما يوفّر نقطة نهاية متوافقة مع A2A.
موفّر النموذج أو حزمة تطوير الوكيل وحدهما لا يشكلان نظير A2A. ضع واجهة التطبيق
وإجراءاته وقاعدة بياناته على مضيف التطبيق المعتاد، ثم اربط بيئة تشغيل الوكيل
من خلال محوّل أو نقطة نهاية A2A الخاصة بها.

يحتوي الاتصال المستضاف على بيانات تعريف نقطة النهاية ووصف للمصادقة. احتفظ بهذه
البيانات مع مورد الوكيل البعيد أو سجل الاتصال. لا تضع رمزًا مميزًا أو سر عميل
في البيان:

```json
{
"id": "foundry-research",
"name": "Foundry Research",
"url": "https://example.services.ai.azure.com/a2a",
"cardUrl": "https://example.services.ai.azure.com/agentCard/v0.3",
"auth": {
"type": "bearer",
"credentialRef": "FOUNDRY_A2A_TOKEN"
}
}
```

`url` هو نقطة نهاية الاستدعاء أو عنوان الأساس. يكون `cardUrl` اختياريًا عندما
يستخدم الاكتشاف `/.well-known/agent-card.json`، واستعمله عندما ينشر الموفّر
بطاقة الوكيل في مكان آخر. يقرأ العميل إصدار البروتوكول من بطاقة الوكيل. عندما
تحذف بطاقة الموفّر الإصدار، مرّر `protocolVersion` مباشرة إلى `A2AClient`.
يصف `auth` كيفية حصول كود الخادم على رمز حامل. الأوصاف المدعومة هي
`bearer` مع `credentialRef` محفوظ في الخزنة، أو `oauth-client-credentials` مع
`tokenUrl` و`clientId` و`clientSecretRef` و`scope`. تشير هذه الحقول إلى أسرار،
ولا تحتوي قيم الأسرار نفسها.

### A2A برمز حامل عام {#generic-bearer-a2a}

استخدم العميل القياسي عندما يقبل النظير `Authorization: Bearer ...`، ويقدّم
بطاقة متوافقة، ويقبل JSON-RPC الخاص بـ Agent-Native:

```ts
const client = new A2AClient(endpoint, token, {
cardUrl,
protocolVersion: "0.3",
});
```

حلّ `token` من جانب الخادم عبر اتصال مساحة العمل أو الخزنة. لا ترسله من كود
المتصفح، ولا تكتبه في البيان، ولا تضعه في مطالبة. مفتاح API الثابت هو اعتماد
للنقل إلى الخدمة البعيدة فقط، ولا ينشئ هوية متصل Agent-Native أو يحمل
`approvedActions`.

### Microsoft Foundry {#microsoft-foundry}

تشغّل [الوكلاء المستضافون في Azure AI Foundry](https://learn.microsoft.com/en-us/azure/foundry/agents/overview)
كود الوكيل أو الحاوية خلف نقطة نهاية وهوية وتوسعة وحالة جلسة ومراقبة مُدارة.
هذا النموذج مخصص لبيئة تشغيل الوكيل. احتفظ بواجهة Agent-Native وإجراءاته
ونشر PostgreSQL على مضيف التطبيق، واستدع نقطة نهاية Foundry من كود الخادم.

يمكن لـ Foundry كشف نقطة نهاية A2A من خلال [Agent Service](https://learn.microsoft.com/en-us/azure/foundry/agents/how-to/enable-agent-to-agent-endpoint).
يتطلب ذلك مصادقة Microsoft Entra، ويحتاج المتصل إلى إذن Foundry Agent
Consumer. استخدم بطاقة وإصدار v0.3 الخاصين بالموفّر مع `cardUrl` و
`protocolVersion` عندما تتحدث نقطة النهاية باستخدام JSON-RPC الخاص بـ
Agent-Native. يجب على موفّر الرموز الحصول على رمز وصول Entra وتجديده. لا
يكفي `A2A_SECRET` أو مفتاح API ثابت لمصادقة Foundry.

لمصادقة بيانات اعتماد كيان الخدمة، اطلب رمز Entra بالنطاق
`https://ai.azure.com/.default` وامنح المتصل دور **Foundry Agent Consumer** على
مستوى المشروع أو الوكيل. خزّن سر العميل في الخزنة وأشر إليه من البيان:

```json
{
"auth": {
"type": "oauth-client-credentials",
"tokenUrl": "https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token",
"clientId": "<application-id>",
"clientSecretRef": "FOUNDRY_CLIENT_SECRET",
"scope": "https://ai.azure.com/.default"
}
}
```

### Gemini Enterprise {#gemini-enterprise}

يمكن لـ [Gemini Enterprise تسجيل وكلاء A2A خارجيين](https://docs.cloud.google.com/gemini/enterprise/docs/register-and-manage-an-a2a-agent)،
كما يمكن لسجل الوكلاء نشر نقطة نهاية وسيطة. تستخدم روابط HTTP+JSON الخاصة به
مسارات يحددها الموفّر: يَستخدم الاكتشاف `GET {url}/v1/card`، والاستدعاء
`POST {url}/v1/message:send`، والبث `POST {url}/v1/message:stream`. تستخدم
الطلبات رموز حامل Google OAuth أو ADC وصلاحيات Google Cloud IAM. راجع
[استدعاء وكيل عبر نقطة نهاية A2A في السجل](https://docs.cloud.google.com/gemini/enterprise/docs/invoke-agent-a2a)
لمتطلبات نقطة النهاية والصلاحيات.

تختلف هذه المسارات عن مسارات JSON-RPC الخاصة بـ Agent-Native
(`/.well-known/agent-card.json` و`/_agent-native/a2a`). سجّل نقطة النهاية بعد
إضافة محوّل يترجم تنسيق السلك ويحصل على بيانات اعتماد Google ويجددها. إذا كان
الهدف يوفّر نقطة نهاية A2A قياسية منفصلة، فاستخدمها مع إرشادات رمز الحامل
العام. لا تمر حركة التسجيل في Gemini Enterprise عبر سياسات Agent Gateway،
لذلك طبّق سياسة المصادقة والتفويض الخاصة بالهدف.

## استدعاء مساحة العمل الآلية {#programmatic-invoke}

بالنسبة لمساحات العمل الأصلية للوكيل، تفضل مساعد `agentNative` عند استخدام الكود أو
Expand Down
Loading
Loading