Skip to content

Add schemas, fixtures, conformance suite, reference impls, and docs - #1

Merged
atulkc merged 5 commits into
mainfrom
complete-repo-artifacts
Oct 2, 2026
Merged

atulkc merged 5 commits into
mainfrom
complete-repo-artifacts

Conversation

@atulkc

@atulkc atulkc commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Turns the spec-only repository into a machine-checkable, implementable, and governed protocol profile, addressing the "What this repository still needs" list in the README.

Spec sections affected

None (no normative changes to spec.md). This PR adds supporting artifacts around the existing Draft v0.1 spec.

What's added

  • schemas/v0.1/ — JSON Schema 2020-12 for every profile payload (Agent Card extension, clientCapabilities, directive metadata, spoken artifacts, each directive, interruption, conversation-history-update) + shared common defs and a versioning README.
  • fixtures/ — valid and invalid payloads per schema (directory name = schema name) plus happy-path and barge-in event sequences.
  • conformance/ — pytest suite with a schema-validation layer and a behavioral layer (negotiation, capability intersection, sequenceId ordering, task lifecycle, barge-in), each test mapped to a spec section. Wired into CI via .github/workflows/conformance.yml.
  • examples/ — Python Live client + Reasoner server over WebSocket JSON-RPC, self-checking four scenarios.
  • docs/ — compatibility matrix, security profile, error/retry policy, escalation design, operational profile.
  • Governance & hygiene — GOVERNANCE.md, DEVELOPING.md, .github/ issue + PR templates, .gitignore, CHANGELOG.md; rewrote CONTRIBUTING.md/SECURITY.md for a spec repo and reconciled README.md.

Validation

  • All 12 schemas are well-formed 2020-12 documents.
  • pytest conformance/ → 36 passed.
  • Reference demo (reasoner_server + live_client) → 8/8 checks passed.
  • No dangling internal Markdown links.

Outstanding (follow-ups, not blocking)

  • CODEOWNERS still has * with no owner assigned — needs a real @org/team.
  • Pinned A2A SDK names/versions in docs/compatibility.md (left as stated draft intent).
  • spec.md status left as Draft v0.1; GOVERNANCE.md documents promotion criteria.
  • docs/escalation.md proposes an escalationOutcome event type kept as flagged future work (not yet in the schema/spec enum).

…docs

Turn the spec-only repo into a machine-checkable, implementable, and governed
protocol profile, addressing the "What this repository still needs" list.

- schemas/v0.1: JSON Schema 2020-12 for every profile payload
- fixtures: valid/invalid payloads per schema + event sequences
- conformance: pytest schema + behavioral suite, wired into CI
- examples: Python Live client + Reasoner server over WebSocket JSON-RPC
- docs: compatibility, security, errors, escalation, operations
- governance: GOVERNANCE.md, DEVELOPING.md, .github templates, CHANGELOG
- hygiene: rewrite CONTRIBUTING.md/SECURITY.md for a spec repo; reconcile README
…d dumps

Pretty-prints every JSON-RPC payload sent and received when -v/--verbose
is passed, to aid manual review of the wire-level message flow. Default
output is unchanged.
…agent

Updates the extension URI path segment across schemas ($id/$ref), fixtures,
spec, docs, and reference implementations. The extension is now identified by
https://schemas.salesforce.com/a2a/ext/realtime-agent/v0.1. Conformance suite
and reference client both pass unchanged.
Comment thread DEVELOPING.md Outdated
pytest conformance/
```

Run the reference implementations end to end (once present):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To run examples, we need to run pip install -r examples/requirements.txt as pre-requisite.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, added it to the prerequisites. I also cleaned up the "(once present)" wording while I was there.

Comment thread schemas/v0.1/interruption.schema.json Outdated
"description": "The DataPart 'data' object the Live layer sends on barge-in, alongside tasks/cancel for the in-flight task (spec §8). The task then transitions to CANCELED and the next utterance begins a new task under the same context (roll-forward model).",
"type": "object",
"required": [
"played_text",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we are working with amazon for A2A, they can't send us any of these fields. So I am thinking we can make all of these fields optional. Without these reasoner has to make best guess ( for eg it can consider all text as unplayed and update the history, use last turn_id for interrupted_turn_id ). Is that acceptable?

@atulkc atulkc Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that makes sense to me. I made all the fields optional and added the fallbacks to section 8. With no played_text, the Reasoner treats everything as unplayed. With no interrupted_task_id, it uses the latest task, and with no request guid it just correlates at the task level. I also added an empty {} fixture so the Amazon case is covered.

Comment thread schemas/v0.1/interruption.schema.json Outdated
"played_text",
"planned_text",
"unspoken_text",
"interrupted_turn_id",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With full-duplex mode in GPT Live, we’re moving away from the concept of a turn-based conversation. So, I think we should rename this to interrupted_task_id.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed. I changed the same field in the escalation outcome payload too so they stay consistent. Should we do the same for turn_id in conversationHistoryUpdate and rta/turnId? I left those alone for now since it's a bigger change, but happy to do it in a follow-up.

"title": "Spoken output artifact",
"description": "An A2A artifact carrying user-facing spoken output, streamed via TaskArtifactUpdateEvent (spec §6.2). Also the shape used by the say_exactly and convey directives on the artifact channel (spec §7); those additionally carry directive metadata (see directive-metadata.schema.json) with renderMode verbatim/paraphrase. Each chunk SHOULD contain both a normalized TextPart (for TTS) and a transcript TextPart (for history/UI); an untagged text part is interpreted as transcript.",
"type": "object",
"required": ["parts"],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add artifactId as required to make sure we always have unique id to track?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. It's required now, and the spec says it has to be unique within the task.

"title": "Agent Card extension entry",
"description": "One entry in the Agent Card's capabilities.extensions[] array advertising the Agentforce Live profile (spec §4). For v0.1 'required' MUST be false.",
"type": "object",
"required": ["uri", "required"],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we mark params as required field to make sure directiveType extensions are always available on agent card?

@atulkc atulkc Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Made params required and added a line in section 4.1 about it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have example that triggers confirm_entities, can we add?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added one. If you say something like "I'd like to pay my bill", the server sends back a confirm_entities, and the client confirms and checks that the turn completes.

Comment thread examples/live_client.py
print(f" [{'PASS' if ok else 'FAIL'}] {name}")


async def run(verbose: bool = False) -> int:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example code doesn't pass content_id in request. can we update it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean context_id, right? Yes, will add it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming you meant contextId, let me know if not! The server now returns it, and the client sends it back on every message after the first turn. I also added a check for it.

Comment thread conformance/test_behavioral.py Outdated


# §6.2 — reaching a terminal A2A state ends the turn
@pytest.mark.parametrize("state", ["COMPLETED", "CANCELED", "FAILED"])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add test for REJECTED terminal state as well?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

Comment thread docs/compatibility.md Outdated
| Profile version | `v0.1` (draft) | Extension URI `https://schemas.salesforce.com/a2a/ext/realtime-agent/v0.1` |
| Core A2A constructs used | `Message`, `Task`, `TaskArtifactUpdateEvent`, `TaskStatusUpdateEvent`, task states, `contextId`/`taskId`, metadata, `TextPart`, `DataPart` | No new RPC methods or task states are defined (spec §1). |
| A2A methods used | `message/stream`, `tasks/cancel` | `tasks/resubscribe` is reserved for a future version (spec §11). |
| Task states relied on | `WORKING`, `INPUT_REQUIRED`, `COMPLETED`, `CANCELED`, `FAILED` | Terminal state — not an SDK `final` flag — is the end-of-turn signal (spec §6.2). |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add REJECTED state here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

Comment thread docs/errors.md Outdated
§5), not by transport/channel order. Consumers MUST reorder by
`afl/sequenceId` rather than assume in-order delivery across artifact and
status event channels.
* Reaching a terminal A2A state (`COMPLETED`, `FAILED`, `CANCELED`) is the

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add REJECTED state here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added. I updated the same list in operations.md too.

atulkc added 2 commits October 1, 2026 19:27
The profile is vendor-agnostic. Rename "Agentforce Live A2A Profile
Extension" to "Realtime Agent A2A Profile Extension" across docs, schema
descriptions, and example docstrings, and rename the afl/ metadata-key
shorthand (and the AFL Python constant) to rta/ / RTA to match the
realtime-agent extension URI. No wire-format change: on-the-wire keys are
already full extension URIs.
Schemas and spec:
- interruption: every field is now optional (some Live layers, e.g. A2A
  integrations that cannot observe playback, can't supply them); spec §8
  documents the Reasoner fallbacks. Rename interrupted_turn_id to
  interrupted_task_id (also in the escalation-outcome payload), since
  full-duplex modes move away from turn-based conversation.
- Require artifactId on spoken artifacts, params on the Agent Card
  extension entry, and cancellation on ask_for / confirm_entities (§7.1).
  Each gets an invalid fixture that isolates the violation.

Examples:
- Add a confirm_entities handoff + resume scenario, with ask_for_data /
  confirm_entities_data builders.
- The Reasoner returns contextId on every event and the client reuses it on
  every later message (spec §3).
- live_client now self-checks 11 scenarios/assertions.

Docs and tests:
- Add REJECTED to the terminal-state lists and the conformance test.
- DEVELOPING.md lists examples/requirements.txt as a prerequisite.
@atulkc
atulkc requested a review from relango October 2, 2026 02:46
@atulkc
atulkc merged commit 6917844 into main Oct 2, 2026
4 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