microsoft / microsoft/agent-host-protocol

Proposal: Collection Attachments

Open
#362 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
344
Forks
122
Avg merge
14h 12m
Merged PRs (30d)
22

Description

Summary

Add a MessageCollectionAttachment that represents multiple heterogeneous attachments as one logical, durable attachment.

This addresses cases where clients present one attachment but the model needs several pieces of context:

  • Browser element: structured text plus an inline screenshot.
  • Directory: directory resource plus eagerly attached images.
  • Future compound resources such as document bundles.

Today these pieces must be flattened into Message.attachments. After replay, clients cannot reliably reconstruct the original logical grouping and render every piece independently.

Proposed shape
export const enum MessageAttachmentKind {
	Simple = 'simple',
	EmbeddedResource = 'embeddedResource',
	Resource = 'resource',
	Annotations = 'annotations',
	Chat = 'chat',
	Collection = 'collection',
}

export type MessageCollectionItem =
	| SimpleMessageAttachment
	| MessageEmbeddedResourceAttachment
	| MessageResourceAttachment
	| MessageAnnotationsAttachment
	| MessageChatAttachment;

/**
 * Multiple attachments presented by the originating client as one logical item.
 *
 * The collection has no model representation of its own. Hosts flatten its
 * attachments when constructing model context, while preserving the collection
 * in durable message state for replay.
 */
export interface MessageCollectionAttachment extends MessageAttachmentBase {
	type: MessageAttachmentKind.Collection;

	/**
	 * Ordered attachments composing this logical item.
	 *
	 * Collections cannot contain other collections.
	 * This array MUST contain at least one attachment.
	 */
	attachments: MessageCollectionItem[];
}

export type MessageAttachment =
	| SimpleMessageAttachment
	| MessageEmbeddedResourceAttachment
	| MessageResourceAttachment
	| MessageAnnotationsAttachment
	| MessageChatAttachment
	| MessageCollectionAttachment;
Semantics
Durable state and presentation
  • The collection is stored in Message.attachments as a single item.
  • Clients SHOULD render it as one logical attachment using the collection’s label, displayKind, and _meta.
  • Clients MAY expose its constituent attachments in expanded or detailed UI.
  • Clients MUST NOT render its members as independent top-level attachments.
Model context

The collection itself has no model representation.

When accepting a message, hosts MUST process each member in order exactly as if it appeared directly in Message.attachments. This is a one-level flattening operation; collection attachments cannot nest.

This keeps AHP focused on durable presentation state while leaving provider-specific model translation to the host.

Ordering and ranges
  • Member order is significant and MUST be preserved.
  • Producers SHOULD place the message-text range on the collection.
  • A member’s range, when present, continues to describe that member.
Metadata

Collection and member metadata are independent:

  • Collection _meta describes the logical item.
  • Member _meta describes that particular model-facing attachment.
  • Hosts MUST preserve both without merging them.
Examples
Browser element
{
	"type": "collection",
	"label": "button#submit",
	"displayKind": "element",
	"attachments": [
		{
			"type": "simple",
			"label": "button#submit structure",
			"modelRepresentation": "Element: button#submit\n\n..."
		},
		{
			"type": "embeddedResource",
			"label": "button#submit screenshot",
			"displayKind": "image",
			"contentType": "image/jpeg",
			"data": "..."
		}
	]
}
Directory with resolved images
{
	"type": "collection",
	"label": "design-assets",
	"displayKind": "directory",
	"attachments": [
		{
			"type": "resource",
			"label": "design-assets",
			"displayKind": "directory",
			"uri": "file:///workspace/design-assets"
		},
		{
			"type": "resource",
			"label": "hero.png",
			"displayKind": "image",
			"uri": "file:///workspace/design-assets/hero.png"
		}
	]
}
Why collections are not recursive

A restricted member union makes cycles and unbounded nesting impossible by construction.

This follows the existing ContainerCustomizationBase / ChildCustomization pattern, where container customization kinds are excluded from the child union. It also avoids requiring runtime recursion rules like those needed for chat attachments.

Compatibility

An unknown collection variant cannot be ignored coherently because doing so also discards all contained model context. Therefore this should not be treated like an optional rendering-only variant.

Recommended rollout:

  1. Introduce it in a new negotiated protocol version.
  2. Hosts speaking an older version flatten collections into ordinary top-level attachments.
  3. Hosts speaking the new version preserve collections in durable state.
  4. If rollout across mixed-version clients requires finer gating, add an attachmentCollections client capability and flatten for clients that do not advertise it.

This preserves today’s degraded behavior—independent attachments—for older clients rather than losing the attachments entirely.

Alternatives considered
Correlation through _meta

Attach a shared UUID to otherwise independent attachments.

This works as an implementation-specific bridge, but clients must understand private metadata and grouping remains best-effort. Once grouping is required for interoperable replay, AHP doctrine recommends graduating it into typed state.

Group fields on flat attachments

Add a group identifier and repeated group metadata to each attachment.

This gives excellent old-client degradation, but loses atomicity, duplicates metadata, and requires clients to reconcile incomplete or inconsistent groups.

Add binary content to SimpleMessageAttachment

This covers text-plus-image but not general one-to-many cases such as directories or document bundles.

Implementation impact

Expected changes in microsoft/agent-host-protocol:

  • Add the kind, interfaces, and union membership in types/channels-chat/state.ts.
  • Document collection acceptance and replay semantics in docs/specification/chat-channel.md.
  • Add a changelog fragment under docs/.changes/.
  • Regenerate schemas and TypeScript, Rust, Kotlin, Swift, and Go clients.
  • Add schema/generator coverage.
  • No reducer changes should be required because existing message-bearing actions already preserve Message.attachments.
Relevant precedent

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with types/channels-chat/state.ts to trace existing attachment unions, then read docs/specification/chat-channel.md and the versioning guidance. Review the schema and client generator coverage before changing the TypeScript, Rust, Kotlin, Swift, and Go outputs. Done means the collection is represented, documented, versioned, generated, and covered by schema/generator tests, with a changelog fragment under docs/.changes/.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, kotlin, rust, swift, typescript
Domain
api, backend-api-design, documentation, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.