Skip to content

canvas: add chat-scoped discovery and URI-addressed lifecycle - #528

Open
Joaquín Ruales (jruales) wants to merge 11 commits into
mainfrom
jruales/ahp-canvas-inventory
Open

Joaquín Ruales (jruales) wants to merge 11 commits into
mainfrom
jruales/ahp-canvas-inventory

Conversation

@jruales

@jruales Joaquín Ruales (jruales) commented Oct 14, 2026 •

Copy link
Copy Markdown

Summary

AHP already projects live Canvas instances through ChatState.canvases and experimental ahp-canvas: channels, but clients also need an authoritative way to discover the Canvas types available to one exact chat and manage a selected Canvas resource.

This PR models discovery as chat state and uses the Canvas channel URI as the resource identity:

  • ChatState.canvasRegistry is the authoritative exact-chat Canvas type registry.
  • chat/canvasRegistryChanged replaces or clears that registry when live provider registration changes.
  • Client-dispatchable chat/canvasRegistryRequested explicitly requests potentially effectful materialization for a persisted cold chat.
  • openCanvas uses a client-chosen ahp-canvas: URI and separately identifies the owning chat and declaration.
  • disposeCanvas closes that URI-addressed Canvas resource.
  • Extension metadata is normalized once per CanvasExtensionDeclaration; nested CanvasTypeDeclaration entries use title and contain only type-local metadata.
  • Extension IDs are opaque. The protocol does not expose VS Code/Copilot-specific extension-source taxonomy.
  • The registry field and actions remain Stability 1 — Experimental and are capability-gated by AgentCapabilities.canvases.

Protocol behavior

Live registry state

For a live chat, the host keeps canvasRegistry synchronized with provider registration and emits chat/canvasRegistryChanged only when the authoritative registry changes. Clients do not poll and do not treat changes to the open-instance list as registry invalidation.

The registry distinguishes three states:

  • absent: not materialized or currently unavailable;
  • { extensions: [] }: materialized, with no available Canvas types;
  • populated: declarations keyed by (extensionId, canvasId).

requiresInput remains so clients can exclude declarations whose input flow they do not support. Speculative action metadata is not part of the registry.

Cold materialization

When a persisted chat is cold, a client may dispatch chat/canvasRegistryRequested. The reducer intentionally leaves optimistic state unchanged while the host may resume the backing runtime, discover extensions, and execute extension startup code. The host then publishes the complete result through chat/canvasRegistryChanged.

Materialization must not create a backing for a brand-new chat, send a user message, or invoke a model.

URI-addressed lifecycle

openCanvas.channel is the client-chosen ahp-canvas: resource URI. Reusing that URI for the same chat and declaration focuses or refreshes the logical instance; reusing it for a different chat, extension, or Canvas type must fail with Conflict.

disposeCanvas.channel identifies the same resource for disposal. CanvasState.instanceId remains provider-facing correlation metadata; the Canvas URI is the AHP resource identity.

sequenceDiagram
    participant C as Client
    participant H as Agent Host

    C->>H: subscribe(chat)
    H-->>C: ChatState snapshot

    opt Registry absent and chat persisted
        C->>H: dispatchAction(chat, canvasRegistryRequested)
        H->>H: Resume runtime and discover providers
        H-->>C: action(chat, canvasRegistryChanged)
    end

    C->>H: openCanvas(canvas, chat, extensionId, canvasId)
    H-->>C: action(chat, canvasesChanged)
    C->>H: subscribe(canvas)
    H-->>C: CanvasState snapshot
    C->>H: disposeCanvas(canvas)
    H-->>C: action(chat, canvasesChanged)
Loading

Compatibility and generated surfaces

  • The change is additive and capability-gated; hosts that omit AgentCapabilities.canvases remain unsupported without probing.
  • The registry actions are introduced in protocol 1.1.0; this PR does not bump the protocol version.
  • Existing server-published Canvas references and channels remain the live-instance mechanism.
  • Canonical TypeScript definitions generate schemas, reference documentation, action-origin metadata, and wire types and command helpers for each language client; native reducers remain hand-written ports validated by shared fixtures.
  • Swift and Kotlin include typed openCanvas / disposeCanvas command helpers, and Swift dispatchability matches the client-dispatchable registry request.
  • Shared reducer and round-trip fixtures cover registry updates, lifecycle commands, and Canvas capability presence across clients.
  • This PR does not define host/runtime implementation, client UI, extension installation or enablement, input-bearing Canvas flows, or pre-session catalogue probing.

Validation

Check Result
npm test Passed: 623 tests; 100% reducer coverage; generated output verified
npm run docs:build Passed
TypeScript npm run typecheck && npm test && npm run build Passed: 77 tests
Rust cargo fmt --all -- --check, cargo clippy --workspace -- -D warnings, cargo test --workspace Passed, including workspace and doc tests
Go go build ./..., gofmt -l, go vet ./..., go test ./... Passed
swift build && swift test Passed: 96 tests
Kotlin ./gradlew build --stacktrace on JDK 17 Passed
.NET interop typecheck, restore, format, Release build, and tests Passed: 688 tests

🤖 Written by GitHub Copilot on behalf of Joaquín Ruales (@jruales).

Comment thread types/channels-canvas/commands.ts Resolved
Comment thread types/channels-canvas/commands.ts Resolved
Comment thread types/channels-canvas/commands.ts Resolved
Comment thread types/channels-canvas/state.ts Resolved
Comment thread types/channels-canvas/state.ts Resolved
@jruales Joaquín Ruales (jruales) changed the title canvas: add discovery and open commands canvas: expose registry state and URI-addressed open Oct 15, 2026
@jruales Joaquín Ruales (jruales) changed the title canvas: expose registry state and URI-addressed open canvas: add chat-scoped discovery and URI-addressed lifecycle Nov 3, 2026
@jruales
Joaquín Ruales (jruales) marked this pull request as ready for review November 3, 2026 08:49
Add capability-gated exact-chat listCanvasTypes and openCanvas commands, including owning extension metadata, and regenerate all protocol clients and schemas.

Co-authored-by: Copilot App <[email protected]>

Copilot-Session: 0a6aa762-4b80-4e33-be5d-68d9f3398af2
Co-authored-by: Copilot App <[email protected]>

Copilot-Session: 0a6aa762-4b80-4e33-be5d-68d9f3398af2
Co-authored-by: Copilot App <[email protected]>

Copilot-Session: 0a6aa762-4b80-4e33-be5d-68d9f3398af2
Replace snapshot-only Canvas listing with an authoritative exact-chat registry, explicit cold materialization action, and URI-addressed Canvas opening. Normalize provider metadata and update every generated client, reducer, fixture, and specification.

Co-authored-by: Copilot App <[email protected]>

Copilot-Session: 0a6aa762-4b80-4e33-be5d-68d9f3398af2

This branch has not been deployed

No deployments
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