Documentation Index
Fetch the complete documentation index at: https://agentstack.beeai.dev/llms.txt
Use this file to discover all available pages before exploring further.
Agent Stack extends the A2A Protocol with
A2A extensions that enable agents to access platform services and
enhance the user interface beyond what the base protocol provides.
Extensions fall into two categories:
- Service extensions: Demands in the agent card that your client fulfills (LLMs, embeddings, OAuth, secrets)
- UI extensions: Message metadata your UI renders (forms, approvals, citations, trajectories)
All extension definitions are exported from agentstack-sdk/extensions if you prefer a narrower import surface.
Core Helpers
The SDK includes helpers for reading and producing extension metadata:
extractServiceExtensionDemands(extension) reads demands from an agent card.
fulfillServiceExtensionDemand(extension) merges fulfillments into metadata.
extractUiExtensionData(extension) reads UI metadata from a message.
resolveUserMetadata(inputs) builds metadata for form, approval, and canvas responses.
handleAgentCard(agentCard) returns demands and a resolveMetadata function.
handleTaskStatusUpdate(event) maps status updates to actionable UI results.
buildMessageBuilder(agentCard) builds user messages with resolved metadata.
Use these directly when you want fine grained control beyond handleAgentCard.
extractServiceExtensionDemands, fulfillServiceExtensionDemand, and extractUiExtensionData are factories. You pass
an extension definition once and reuse the returned function for that extension.
For end to end usage, see A2A Client Integration and User Messages.
Service Extensions
Service extensions use a dependency injection pattern. The agent declares demands and the client provides fulfillments.
LLM Service
Provides OpenAI compatible LLM access with api_base, api_key, and api_model.
import { buildLLMExtensionFulfillmentResolver, handleAgentCard } from 'agentstack-sdk';
const { resolveMetadata } = handleAgentCard(agentCard);
const llmResolver = buildLLMExtensionFulfillmentResolver(api, contextToken);
const metadata = await resolveMetadata({
llm: llmResolver,
});
Embedding Service
Provides OpenAI compatible embedding access with api_base, api_key, and api_model.
import { handleAgentCard } from 'agentstack-sdk';
const { resolveMetadata } = handleAgentCard(agentCard);
const metadata = await resolveMetadata({
embedding: async (demands) => ({
embedding_fulfillments: Object.fromEntries(
Object.keys(demands.embedding_demands).map((key) => [
key,
{
identifier: 'openai/text-embedding-3-small',
api_base: 'https://api.openai.com/v1',
api_key: 'your-api-key',
api_model: 'text-embedding-3-small',
},
]),
),
}),
});
MCP
Provides Model Context Protocol transports for tool and connector access.
import { MCPTransportType, handleAgentCard } from 'agentstack-sdk';
const { resolveMetadata } = handleAgentCard(agentCard);
const metadata = await resolveMetadata({
mcp: async (demands) => ({
mcp_fulfillments: Object.fromEntries(
Object.keys(demands.mcp_demands).map((key) => [
key,
{
transport: {
type: MCPTransportType.StreamableHttp,
url: 'https://mcp.example.com',
headers: { Authorization: 'Bearer token' },
},
},
]),
),
}),
});
OAuth
Provides OAuth redirect metadata for authentication flows.
import { handleAgentCard } from 'agentstack-sdk';
const { resolveMetadata } = handleAgentCard(agentCard);
const metadata = await resolveMetadata({
oauth: async (demands) => ({
oauth_fulfillments: Object.fromEntries(
Object.keys(demands.oauth_demands).map((key) => [
key,
{ redirect_uri: 'https://app.example.com/oauth/callback' },
]),
),
}),
oauthRedirectUri: () => 'https://app.example.com/oauth/callback',
});
Secrets
Provides secret values required by the agent.
import { handleAgentCard } from 'agentstack-sdk';
const { resolveMetadata } = handleAgentCard(agentCard);
const metadata = await resolveMetadata({
secrets: async (demands) => ({
secret_fulfillments: Object.fromEntries(
Object.keys(demands.secret_demands).map((key) => [key, { secret: 'your-secret' }]),
),
}),
});
Settings (deprecated)
Deprecated. Planned for removal in the next release. Use Settings Form instead.
This extension lives under ui/settings in the SDK, but it is treated as a service extension because it carries demands
and fulfillments.
import { handleAgentCard } from 'agentstack-sdk';
const { resolveMetadata } = handleAgentCard(agentCard);
const metadata = await resolveMetadata({
settings: async (demands) => ({
values: Object.fromEntries(
demands.fields.map((field) => {
if (field.type === 'single_select') {
return [field.id, { type: 'single_select', value: field.default_value }];
}
return [
field.id,
{
type: 'checkbox_group',
values: Object.fromEntries(
field.fields.map((checkbox) => [checkbox.id, { value: checkbox.default_value }]),
),
},
];
}),
),
}),
});
Migration guide
- Agent cards: replace the
ui/settings extension with the services/form extension and move settings fields to form_demands.settings_form.
- Single select: change type
single_select to singleselect, and change options items from { value } to { id }.
- Checkbox group:
checkbox_group now requires a non empty label.
- Checkbox items:
checkbox now requires content for the visible text. Keep label populated too and map the legacy checkbox label to content when migrating.
- Fulfillments: change checkbox group values from
{ values: { [id]: { value } } } to { value: { [id]: boolean | null } }.
Provides form responses when the agent requests structured input.
import { handleAgentCard } from 'agentstack-sdk';
const { resolveMetadata } = handleAgentCard(agentCard);
const metadata = await resolveMetadata({
form: async () => ({
form_fulfillments: {
default: {
values: { name: 'Ada' },
},
},
}),
});
Settings UI is delivered through the Form service extension. Agents request settings with form_demands.settings_form, and clients respond with form_fulfillments.settings_form.
import { handleAgentCard } from "agentstack-sdk";
const { resolveMetadata } = handleAgentCard(agentCard);
const metadata = await resolveMetadata({
form: async (demands) => {
const settingsForm = demands.form_demands.settings_form;
if (!settingsForm) {
return { form_fulfillments: {} };
}
return {
form_fulfillments: {
settings_form: {
values: Object.fromEntries(
settingsForm.fields.map((field) => {
if (field.type === "singleselect") {
return [
field.id,
{
type: "singleselect",
value: field.default_value
}
];
}
if (field.type === "checkbox_group") {
return [
field.id,
{
type: "checkbox_group",
value: Object.fromEntries(
field.fields.map((checkbox) => [checkbox.id, checkbox.default_value]),
),
},
];
}
throw new Error("Unsupported settings field type");
}),
),
},
},
};
},
});
Prefer settings_form when both settings_form and legacy settings demands are present.
Adds context token metadata so the agent can call platform services. This is typically used only when you cannot pass
the token through A2A client headers. getContextToken is deprecated and kept for backward compatibility. Prefer
passing the context token via A2A client headers when possible.
import { handleAgentCard } from 'agentstack-sdk';
const { resolveMetadata } = handleAgentCard(agentCard);
const metadata = await resolveMetadata({
getContextToken: () => contextToken,
});
getContextToken is deprecated. Prefer sending the context token via A2A client headers when possible.
UI Extensions
UI extensions are message metadata your UI can render. The SDK includes typed schemas for extracting these payloads.
Requests a form render payload.
import { extractUiExtensionData, formRequestExtension } from 'agentstack-sdk';
const readForm = extractUiExtensionData(formRequestExtension);
const form = readForm(message.metadata);
Approval
Requests user approval for an action or tool call.
import { approvalExtension, extractUiExtensionData } from 'agentstack-sdk';
const readApproval = extractUiExtensionData(approvalExtension);
const approval = readApproval(message.metadata);
Canvas
Requests a canvas edit with indices and description.
import { canvasExtension, extractUiExtensionData } from 'agentstack-sdk';
const readCanvas = extractUiExtensionData(canvasExtension);
const request = readCanvas(message.metadata);
Citation
Provides citation ranges and URLs for inline references.
import { citationExtension, extractUiExtensionData } from 'agentstack-sdk';
const readCitations = extractUiExtensionData(citationExtension);
const citations = readCitations(message.metadata);
Trajectory
Provides trace entries for reasoning or execution steps.
import { extractUiExtensionData, trajectoryExtension } from 'agentstack-sdk';
const readTrajectory = extractUiExtensionData(trajectoryExtension);
const trajectory = readTrajectory(message.metadata);
Agent Detail
Provides agent metadata to display in the UI. This extension is sent in the agent card capabilities, not in message
metadata.
import { agentDetailExtension, extractUiExtensionData } from 'agentstack-sdk';
const readAgentDetail = extractUiExtensionData(agentDetailExtension);
const uri = agentDetailExtension.getUri();
const params = agentCard.capabilities.extensions?.find((extension) => extension.uri === uri)?.params;
const agentDetail = params ? readAgentDetail({ [uri]: params }) : null;
Error
Provides structured error information.
import { errorExtension, extractUiExtensionData } from 'agentstack-sdk';
const readError = extractUiExtensionData(errorExtension);
const error = readError(message.metadata);
OAuth Request
Provides an OAuth authorization endpoint to redirect the user.
import { extractUiExtensionData, oauthRequestExtension } from 'agentstack-sdk';
const readOAuth = extractUiExtensionData(oauthRequestExtension);
const oauthRequest = readOAuth(message.metadata);
Secrets Request
Provides secret demand prompts.
import { extractUiExtensionData, secretsRequestExtension } from 'agentstack-sdk';
const readSecrets = extractUiExtensionData(secretsRequestExtension);
const secretDemands = readSecrets(message.metadata);
Handling task status updates
Use handleTaskStatusUpdate to parse status updates into UI actions. This covers OAuth, secrets, forms, and approval
flows.
import { handleTaskStatusUpdate, TaskStatusUpdateType } from 'agentstack-sdk';
for await (const event of stream) {
if (event.kind === 'status-update') {
handleTaskStatusUpdate(event).forEach((result) => {
switch (result.type) {
case TaskStatusUpdateType.FormRequired:
// Render result.form
break;
case TaskStatusUpdateType.OAuthRequired:
// Redirect to result.url
break;
case TaskStatusUpdateType.SecretRequired:
// Prompt for result.demands
break;
case TaskStatusUpdateType.ApprovalRequired:
// Ask the user to approve result.request
break;
case TaskStatusUpdateType.TextInputRequired:
// Prompt for text input
}
});
}
}
When the user responds to a form, approval, or canvas request, use resolveUserMetadata to build message metadata:
import { resolveUserMetadata } from 'agentstack-sdk';
const metadata = await resolveUserMetadata({
form: formValues,
approvalResponse: { decision: 'approve' },
canvasEditRequest: {
start_index: 0,
end_index: 12,
artifact_id: 'artifact-id',
description: 'Replace the title',
},
});
Type Safety
All extension schemas are typed in TypeScript and validated with Zod at runtime. This helps catch malformed extension
payloads early and keeps your UI logic aligned with the protocol.