Skip to content

fix(sample): align the negotiation cases with the spec and rewrite the chapter in plain language - #84

Merged
zhangwenjun-huawei merged 30 commits into
project-openan:mainfrom
codetalks-hw:docs/ran-energy-saving-negotiation-business-language
Oct 20, 2026
Merged

zhangwenjun-huawei merged 30 commits into
project-openan:mainfrom
codetalks-hw:docs/ran-energy-saving-negotiation-business-language

Conversation

@codetalks-hw

@codetalks-hw codetalks-hw commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Context

PR #83 was merged (871871a) with head 9c0e0c9; two documentation commits were pushed after the merge and stranded. This PR carries those two commits plus the subsequent SE review rounds. 6 DCO-signed commits, sample-only (src/a2a_t/ untouched).

What changed

1. Business language instead of internal state (6ea2794, 508e6e0)

  • §4.1 opens with the three situations in business terms, not validation error codes.
  • §4.2's four-message loop is described as business actions — no TASK_STATE_*, no task framing.
  • TASK_STATE_* is not an A2A-T SDK concept: src/a2a_t/ has zero INPUT_REQUIRED references. It is an A2A protocol TaskState used by the sample to carry the propose; it remains in the docs only where it is an implementation fact (§3.3, §6.1).
  • The client can accept, reject or abort, so the templateUri dispatch is described as picking "its answer", not "the accept".

2. Case alignment with the negotiation spec (3e9b5eb)

The sample's target and feasibility cases had drifted from docs-local/A2A-T-协商规范.md. Rebuilt to match, including the message forms the spec uses:

Spec case Before Now
1. region missing missing region unchanged
2. overlapping time segments 100 Mbps beyond cell capability {17:30~23:00,20Mbps} and {20:00~00:00,10Mbps} overlap; propose = intent_understanding + request_for_clarification; accept = corrected segments
3. guaranteed rate cannot sustain the outage 30 % goal vs 50 Mbps two stations, 00:0018:00 outage, {06:00~18:00,10Mbps} cannot sustain 18 h; propose = PROPOSE_ALTERNATIVE_ON_FAILURE + infeasibility_details_and_proposal; accept = lower 06:0018:00 to 2 Mbps
  • 16 mock JSON files (8 per language) rewritten.
  • negotiation_filled_params(negotiation_kind, ...) is now kind-aware, so the refilled Task-T prompt carries the agreed target and the continuation re-validates.
  • Mock routing markers use values the failing input carries and the refill does not (20:00~00:00,10Mbps / 06:00~18:00,10Mbps).
  • seam → integration point in the sample docstrings, matching the INTEGRATION POINT annotations.

3. Plain-language chapter rewrite (105e679, 4f2fe38, 2c50e5e, f8e0c1d)

  • §4.1 (three cases) and §4.2 (how the demo decides) are separate subsections; later sections renumbered to 4.3–4.8.
  • Message 3: the request is re-sent with the missing or corrected content and the answer rides in that same message — it no longer reads as two messages.
  • templateUri described by what it is (the prompt template the message text was rendered from), then how the client uses it.
  • "generation channels (fromData / fromText)" → "generated from structured data or from natural language", in the sample READMEs and the --channel help.
  • "decision seam" → "where your decision plugs in" / integration point (README + code docstrings).
  • run_demo.py --help describes the new cases; the four-message loop covers all three cases.
  • The feasibility narrative no longer claims the server provides "the evidence": the demo cannot produce an assessment basis, so the basis item is gone from the scenario data and mock resources (conclusion + proposal remain).
  • A table of contents covers sections 1–6 in both languages.
  • §4.3 now states that the protocol is symmetric — either side can open a negotiation. The demo's server-proposes choice is scenario-specific, both facades expose the same generation and validation methods, and a customer whose client proposes puts the decision on the server side.

Verification

  • 151 sample tests pass; ruff clean; ty 39 (baseline, no new classes).
  • Live runs: information (zh), target (zh + en over fromText), feasibility (zh + en over fromText) all end TASK_STATE_COMPLETED, events=14 artifacts=1; the rendered proposes carry the spec's time-overlap and outage content.
  • src/a2a_t/ untouched — sample data, mock resources, tests and docs only.
  • Both READMEs keep a parallel heading structure; every internal anchor resolves.

Increment 3 — explicit roles instead of "you" (268b9cb, 679a699)

Production splits the two agents across companies: the server agent is typically another vendor's system, while the client agent is the one this sample helps implement. The README addressed both as "you", leaving every responsibility paragraph ambiguous.

  • Audience stated up front: the client agent's implementers, with the server agent as a runnable reference counterpart.
  • §3.4 and the per-kind ④ sections now say what the client must provide and, separately, what belongs to the server agent (e.g. "the propose wording belongs to the server agent", "which situation applies is the server agent's business decision").
  • §5 replace checklist gains an ownership column (client / server / both), so the client team can see its own rows at a glance.
  • Second-person wording removed from the sample docstrings too (INTEGRATION POINT comments now name the side).
  • Verified: no you/your remains in the sample docs or source; both READMEs' anchors resolve; 151 tests, ruff, ty 39 unchanged.

Increment 4 — reference-table order, trigger code, readability (e492732)

  • Row order fixed. The per-kind tables listed "Client accept" before "Answer source", but the flow is decision-then-render. All three tables now read: Server propose → Client decision → Client accept.
  • Feasibility trigger code changed. The case is a target that cannot be achieved, not a semantic conflict, so the mock and the _NEGOTIATION_TYPE_BY_ERROR_CODE mapping now use content.rule_violation (the content.* catalogue has no dedicated "infeasible" code; this is the closest). Updated in both mock trees, the mapping constant, comments, tests and docs.
  • Readable code references. The long inline signatures are replaced by short method names in the table plus a syntax-highlighted python block per kind showing the server call, the client decision, and the client accept in flow order.
  • Removed the "also supports other forms" notes for TargetProposeContent and FeasibilityProposeContent; the four-part template now describes only the form the sample uses.
  • Stale server_flow.py line anchors refreshed (207→208, 486→495).
  • Verified: 151 tests, ruff clean, ty 39; a live feasibility run completes with the new trigger code.

Increment 5 — client sections stay client-only, plainer wording (39c478d)

  • The feasibility ④ paragraph no longer prescribes where the client's answer comes from (planning / simulation / power-capacity), and the client sections no longer describe what the server agent owns — the per-kind table already labels the server's propose step.
  • wire replaced with plainer wording across the README and the sample docstrings (protocol details / message format / message handling); the Chinese 接线 replaced with 实现 / 判断方式.
  • Verified: 151 tests, ruff clean, ty 39; anchors resolve.

Increment 6 — remaining wire/wired/wiring removed (4e4142f)

The first pass left wired, wires and wiring in the README, the runtime decision log and the test comments. All replaced: the log now reads (not implemented in this demo; see the sample README) and the three assertions pinning it are updated. grep -i 'wire|wires|wired|wiring' over the whole sample is now empty (wireless-network wording excepted).

Increment 7 — propose from text; reject/abort simplified (c1cfe00, 303c34d)

  • The server propose is now generated from a natural-language business message via generate_negotiation_propose_prompt_from_text (the SDK extracts the structured content, then renders the template). The from-data propose builder and the server-side channel plumbing are removed; execute_server_flow no longer takes a channel. The accept remains the client's decision and keeps its --channel switch.
  • The propose-extraction mock mirrors the demo's single missing item and re-adds the relationship note when multiple items are requested.
  • The reject/abort section is now a short paragraph. "Extension point" is gone from the heading and the implementation walkthrough is removed: the client can answer with reject/abort, the demo only implements accept, and the SDK provides the methods when needed.
  • §4.8 and the --channel descriptions now state the accurate scope: the propose is always from text; the flag selects how the client generates its accept.
  • Verified: 145 tests (6 redundant channel tests removed), ruff clean, ty 39; live runs of information/target/feasibility all TASK_STATE_COMPLETED, events=14 artifacts=1.

Increment 8 — name which SDK owns which part (2702c6d)

The boundary statement said "the SDK handles the protocol details", but two SDKs are involved. It now states: the A2A-T SDK generates and validates the negotiation messages (rendering, session map), the A2A SDK carries them (transport), and the A2A-T SDK has no transport layer of its own. The places that refer only to message generation now say "the A2A-T SDK".

Increment 9 — example comments match the step table (8263254)

The per-kind code blocks now start each part with the table's step wording (Server propose / Client decision / Client accept); the client part is split into two comments so all three rows line up.

Increment 10 — from-text accept, channel removed (b5a5702, ee2cec5)

  • The client now generates the accept from a natural-language business message via generate_negotiation_accept_prompt_from_text, mirroring the propose. The accept text is "Accept." plus the numbered values, the confirmed intent, or the feasibility summary.
  • With both messages generated from text, the channel switch has no effect and is removed: --channel, A2AT_SAMPLE_CHANNEL, the channel resolvers, the from-data accept builder and all channel plumbing (client flow, assembly, launcher, env example, tests).
  • Docs updated: the per-kind tables/code blocks show the from-text accept; section 4.8 and the two channel rows are gone; the "remap codes … unmapped failure is rejected" parenthetical in 4.2 is removed as requested.
  • Verified: 142 tests (removed channel-specific tests), ruff clean, ty 39; live information/target/feasibility runs all events=14 artifacts=1.

Increment 11 — formal headings and wording (84e12ba)

  • Sample root README (en/zh): the ran-energy-saving row no longer lists message-generation or webhook details.
  • §1: "over the A2A protocol"; the negotiation line now describes the requirement (needs completion or correction) rather than "not executable as-is"; the three conversational reading paths are replaced by three usage paths.
  • §4.1 → Negotiation scenarios / 协商场景; §4.2 → How the demo selects the negotiation kind / 样例如何选择协商类型.
  • §4.3 → Mechanics common to all kinds / 通用机制; the round definition is now a formal statement (a round is one propose plus the accept/reject that answers it).
  • Per-kind subheadings standardized: ① Trigger condition · ② Reference implementation · ③ Reusable client code · ④ Client-specific code (with the Chinese equivalents).
  • §5 → Deployment checklist / 部署清单; every cross-reference and TOC entry was updated.
  • All internal anchors verified to resolve in both languages.

Increment 12 — external review findings (40f3ca2, 7a29d66)

Two external reviews were checked against the code and docs-local/A2A-T-协商规范.md.

  • Factual fixes: SSE streaming calls message:stream, not message:send (verified against the a2a-sdk REST transport); a round's response can also be abort; the §4 boundary no longer implies SDK-held session state; the mock registry is a both component (server registers, client queries); scenario_data is not removable until both sides are replaced.
  • Clarifications: NegotiationDecision payloads; the negotiation_params / filled_params relation; reject/abort semantics and the consequence of ending without a message; target wording unified to "self-contradictory"; per-client secrets; "a2a-sdk client".
  • Readability: §1–§6 rewritten in shorter sentences; the four-message loop and the end-signal paragraph no longer use patch-style wording; prerequisites state Python 3.12+; §6.3 gives the explicit registry → server → client order and the repository root.
  • Maintainability: line-number links replaced by file links plus function names (_emit_negotiation_propose, _plan_negotiation_accept, _build_negotiation_accept_request, …).
  • Code: _build_request_metadata → _build_request_text (it returns the text part).
  • Kept as is: the three per-kind reference tables (each per-kind section stays self-contained) and the four-part per-kind structure.
  • Verified: 142 tests pass, ruff check clean, all internal anchors resolve in both languages.

Increment 13 — overview restructured around the workflows (2e89035)

  • §1 now follows the requested shape: a short paragraph on A2A-T agent collaboration, then Key workflows with two labelled pipelines — Task-T without negotiation, and Task-T + Negotiation-T with negotiation.
  • The three usage paths are removed; the table of contents already provides navigation.
  • The target case is called ambiguous consistently in §1, §4.1 and §4.5 (en/zh).

Increment 13 follow-up (5fd2535): §4.2 "prescribe" → "dictate".

Increment 14 — custom client agent notes (aee2729)

  • §3.4 renamed to Notes for custom client agent development / 自定义客户端 Agent 开发说明 and split by content:
    • 3.4.1 Client input
    • 3.4.2 Template and parameter schema
    • 3.4.3 Server-side execution
  • The table of contents lists the new subsections; all anchors resolve.

Increment 15 — merge §3.4 into the deployment checklist (20ce5b2)

  • §3.4 is removed; §5 is now the single place that answers "what does each side replace":
    • new row: task template and parameter schema (agreed by both parties);
    • the scenario-data row now also covers the Task-T natural-language input.
  • §3 ends with a one-line pointer to §5; the 3.4.x TOC entries are removed.

Increment 16 — section 5 title (a848959)

  • §5 is now Notes for Custom Agent Development / 自定义 Agent 开发说明 (was "Deployment checklist"); the TOC and all cross-references are updated.

Increment 17 — section 5 intro (23e47fc)

  • The server rows are now described in the same form as the client rows: "the server agent is responsible for the rows marked server" (replacing "what the counterpart replaces in a real system").

Increment 18 — pre-task negotiation, long-running task, site-level schema (60111ac, db3975e)

  • Pre-task negotiation: the propose is a standalone A2A Message (role ROLE_AGENT, same context id, no task id), not a TASK_STATE_INPUT_REQUIRED status update. The server validates before creating a task; the task (SUBMITTED → WORKING) is created only when the accept's Task-T prompt validates. The client detects the propose Message (SSE event or webhook RPC reply), sends the accept without a task id, and registers its own inline push config in webhook mode. INPUT_REQUIRED is gone.
  • No completion: the energy-saving task is a long-running duty task; the continuation no longer emits TASK_STATE_COMPLETED. Every scenario ends on the report artifact and the task stays WORKING. COMPLETED_MESSAGE is removed.
  • Site-level schema: TASK_PARAM_SCHEMA adds optional siteList and backgroundEvent (outage period); the feasibility validation mocks carry them.
  • Refill fidelity: new *_refill mock stages/files make the accept re-send the accepted target (corrected segments / lowered rate) and the site-level outage instead of the canned complete prompt.
  • Chinese comments removed from the sample code and docstrings (zh-CN scenario data/mock resources stay by design).
  • Verified: 143 tests pass, ruff clean; live information (SSE), target, feasibility (SSE) and information (webhook) all end on the report artifact with events=13 artifacts=1 and no terminal state.

Increment 19 (7820ba1): the README no longer uses the undefined "UC1" abbreviation (§1.1 and §5 now describe the demo execution and its scripted progress/report data).

The four-message loop named A2A task states, and the "when a negotiation
happens" section opened with the demo's validation error codes. Both read as
internal implementation detail and did not say when a real deployment would
negotiate.

- 4.1 now opens with the three situations in business terms (an incomplete
  request, a target beyond the server's capability, a goal that may be
  impossible under current conditions) and only then explains how the demo
  wires the trigger; the error-code table becomes a sample-convention note
- 4.2's four messages are described as business actions with no task states
  and no task framing, since a negotiation does not need a created task
- the per-kind "when it opens" lines lead with the business condition and
  mention the demo's error code parenthetically
- the chapter intro no longer frames every negotiation as a validation failure

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…patch

The client does not only accept a propose: it can reject or abort too. The
dispatch on the propose's templateUri selects which answer to build, so the
wording must not narrow it to accept.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
@codetalks-hw
codetalks-hw requested a review from a team as a code owner October 19, 2026 14:06
…ion spec

The sample's two negotiation cases had drifted from the canonical cases in
the A2A-T negotiation spec. Rebuild them to match, including the message forms
the spec uses.

- target: two overlapping time segments ({17:30~23:00,20Mbps} and
  {20:00~00:00,10Mbps}) instead of a rate beyond cell capability; the propose
  now uses the clarification form (intent_understanding +
  request_for_clarification) and the accept carries the corrected segments
- feasibility: stations must hold a guaranteed rate through an 18-hour outage
  but cannot sustain it; the propose now uses PROPOSE_ALTERNATIVE_ON_FAILURE
  with infeasibility_details_and_proposal, and the accept agrees to lower the
  06:00~18:00 rate from 10Mbps to 2Mbps
- negotiation_filled_params is now negotiation-kind aware, so the refilled
  Task-T prompt carries the agreed target and the continuation re-validates
- mock routing markers use values the failing input carries and the refill does
  not, keeping the continuation on the complete variant
- caller-facing jargon replaced: "seam" -> "integration point" in the sample
  docstrings, matching the INTEGRATION POINT annotations

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Second SE review pass over the Negotiation-T chapter.

- the three cases now match the spec: the target case is the overlapping
  time segments, the feasibility case the outage whose duration the
  guaranteed rate cannot sustain
- "when a negotiation happens" and "how the demo decides" are separate
  subsections instead of one section with two topics
- message 3 says the request is re-sent with the missing or corrected
  content and that the answer travels in that same message, so it no longer
  reads as two messages
- templateUri is described by what it is (the prompt template the message
  text was rendered from) and, separately, how the client uses it
- "decision seam" -> "where your decision plugs in" / integration point;
  "generation channels (fromData / fromText)" -> generated from structured
  data or from natural language

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
@codetalks-hw codetalks-hw changed the title docs(sample): describe negotiation in business terms, not internal state fix(sample): align the negotiation cases with the spec and rewrite the chapter in plain language Oct 19, 2026
The --negotiation help and the usage examples still described the retired
100Mbps / 30%-vs-50Mbps inputs.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
The feasibility narrative said the server reports the infeasibility "together
with the evidence", but the demo cannot produce an assessment basis — the
mock only returns canned content. Remove the basis item from the scenario
data and the mock resources, and reword the narrative to "reports that the
target is infeasible and proposes an alternative".

Also add a table of contents to both READMEs, covering sections 1–6.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
The demo has the server propose because the server is the side that finds the
request unexecutable, but the protocol is symmetric: both facades expose the
same propose/accept/reject/abort generation methods and validation methods.
State that explicitly, note that the choice is this scenario's, and point out
where the decision lives if a customer's client opens the negotiation.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Production splits the two agents across companies: the server agent is typically
another vendor's system, while the client agent is the one this sample is meant
to help implement. The README addressed both as "you", which made every
responsibility paragraph ambiguous.

- state the audience up front: the client agent's implementers, with the server
  agent as a runnable reference counterpart
- 3.4 and the per-kind ④ sections now say what the client must provide and, where
  it applies, what belongs to the server agent ("the server agent's business
  decision", "the propose wording belongs to the server agent")
- the replace checklist gains an ownership column (client / server / both)
- second-person wording removed from the sample docstrings as well

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…rigger code

- the tables listed the accept generation before the decision that produces
  it; the real order is server propose -> client decision -> client accept
- the feasibility case is a target that cannot be achieved, not a semantic
  conflict: switch its trigger code from content.semantic_conflict to
  content.rule_violation (mock, mapping, comments, tests, docs)
- replace the long inline signatures with short method names plus a
  syntax-highlighted Python block per kind, showing both sides in flow order
- drop the "also supports other forms" notes for the target and feasibility
  propose content; the four-part template now covers only what the sample uses
- refresh the stale server_flow line anchors

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…jargon

- the feasibility ④ paragraph no longer prescribes where the client's answer
  comes from (planning / simulation / power-capacity), and the client sections
  no longer describe what the server agent owns — the per-kind table already
  labels the server's propose step
- "wire" replaced with plainer wording throughout the README and the sample
  docstrings (protocol details / message format / message handling), and the
  Chinese "接线" replaced with 实现 / 判断方式

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
The README and docstrings still used "wired", "wires" and "wiring" after the
first pass. Replace them with plain wording, including the runtime decision
log, which now reads "(not implemented in this demo; see the sample README)";
the three test assertions pinning that line are updated with it.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
… message

The propose is a business message written by the server agent, so generate it
through generate_negotiation_propose_prompt_from_text: the SDK extracts the
structured content and renders the template. The accept remains the client's
decision and keeps its --channel switch.

- drop the from-data propose builder and the now-unused server-side channel
  plumbing; execute_server_flow no longer takes a channel
- the propose-extraction mock mirrors the demo's single missing item and
  re-adds the relationship note when the input asks for multiple items
- tests: call logs include the propose extraction, the from-channel pairs and
  the channel-plumbing tests are folded or removed

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…ose generation

- "reject and abort" is now a short paragraph: the client may answer with
  reject/abort, the demo only implements accept, the SDK provides the methods
  when needed; the "extension point" wording and the implementation walkthrough
  are removed
- 4.8 states that the propose is always generated from a business message and
  that --channel selects how the client generates its accept
- the channel descriptions in the flags/config tables follow that scope
- line anchors refreshed after the code removal

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
The boundary statement said "the SDK handles the protocol details", but two
SDKs are involved: the A2A-T SDK generates and validates the negotiation
messages, and the A2A SDK carries them. The A2A-T SDK has no transport layer
of its own. State that once at the chapter boundary and use "the A2A-T SDK"
in the places that refer to message generation only.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
The per-kind code blocks now open each part with the same wording as the step
table (Server propose / Client decision / Client accept), and the client part
is split in two so all three rows have a matching comment.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
The client writes the accept as a business message ("Accept." plus the
values, the confirmed intent or the feasibility summary) and generates it
through generate_negotiation_accept_prompt_from_text, mirroring the propose.

With both messages now generated from text, the generation-channel switch has
no remaining effect: remove --channel, A2AT_SAMPLE_CHANNEL, the channel
resolvers and the from-data accept builder. The client flow, assembly, launcher
and tests drop the channel plumbing; the accept assertions now pin the rendered
text and the extraction call.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
- the per-kind tables and code blocks use
  generate_negotiation_accept_prompt_from_text, with the accept text built
  from the decision (numbered values / confirmed intent / summary)
- section 4.8 ("structured data or natural language") and the --channel /
  A2AT_SAMPLE_CHANNEL rows are removed, since every negotiation message is
  now generated from text
- the "remap codes / unmapped failure is rejected" parenthetical in 4.2 is
  removed as requested

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
…ment notes

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
The propose is a standalone Message before task creation (no INPUT_REQUIRED); the task is created on the accepted prompt and stays WORKING (no COMPLETED). The parameter schema covers the site-level outage, and the refill mocks render the accepted values. Chinese code comments and docstrings are removed.

Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
Signed-off-by: codetalks-hw <lihaizhen5@huawei.com>
@zhangwenjun-huawei
zhangwenjun-huawei merged commit d0d4934 into project-openan:main Oct 20, 2026
5 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