diff --git a/phases/16-multi-agent-and-swarms/03-communication-protocols/docs/en.md b/phases/16-multi-agent-and-swarms/03-communication-protocols/docs/en.md
index 237772ba9..ff6776538 100644
--- a/phases/16-multi-agent-and-swarms/03-communication-protocols/docs/en.md
+++ b/phases/16-multi-agent-and-swarms/03-communication-protocols/docs/en.md
@@ -38,16 +38,11 @@ This lesson goes deep. You will read real wire formats from each spec, build wor
Think of these four protocols as layers, each addressing a different question:
```mermaid
-block-beta
- columns 1
- block:ANP["ANP — How do agents trust strangers?\nDecentralized identity (DID), E2EE, meta-protocol"]
- end
- block:A2A["A2A — How do agents collaborate on goals?\nAgent Cards, task lifecycle, streaming, negotiation"]
- end
- block:ACP["ACP — How do agents talk in auditable systems?\nRuns, trajectory metadata, session continuity"]
- end
- block:MCP["MCP — How does an agent use a tool?\nTool discovery, execution, context sharing"]
- end
+flowchart TD
+ ANP["ANP — How do agents trust strangers?
Decentralized identity (DID), E2EE, meta-protocol"]
+ A2A["A2A — How do agents collaborate on goals?
Agent Cards, task lifecycle, streaming, negotiation"]
+ ACP["ACP — How do agents talk in auditable systems?
Runs, trajectory metadata, session continuity"]
+ MCP["MCP — How does an agent use a tool?
Tool discovery, execution, context sharing"]
style ANP fill:#f3e8ff,stroke:#7c3aed
style A2A fill:#dbeafe,stroke:#2563eb
@@ -191,7 +186,11 @@ stateDiagram-v2
canceled --> [*]
rejected --> [*]
- note right of completed: Terminal states are immutable.\nFollow-ups create new tasks\nwithin the same contextId.
+ note right of completed
+ Terminal states are immutable.
+ Follow-ups create new tasks
+ within the same contextId.
+ end note
```
All 8 states (the spec also defines `UNSPECIFIED` as a sentinel, omitted here):
diff --git a/site/lesson.html b/site/lesson.html
index 6ab9b8782..ad76aa84d 100644
--- a/site/lesson.html
+++ b/site/lesson.html
@@ -2094,7 +2094,7 @@
}
function parseMd(md) {
- var lines = md.split('\n');
+ var lines = md.split(/\r?\n/);
var out = '';
var inCodeBlock = false;
var codeLang = '';
@@ -2149,7 +2149,7 @@
for (var ri = 2; ri < tableRows.length; ri++) {
var cells = tableRows[ri];
h += '
';
- for (var ci = 0; ci < cells.length; ci++) {
+ for (var ci = 0; ci < headers.length; ci++) {
var cls = '';
if (isKeyTerms) {
var headerLower = (headers[ci] || '').toLowerCase();
@@ -2216,12 +2216,11 @@
continue;
}
- if (line.match(/^\|.+\|/)) {
+ if (line.match(/^\s*\|.*\|\s*$/)) {
out += flushList();
out += flushBlockquote();
if (!inTable) inTable = true;
- var cells = line.split('|').slice(1, -1);
- tableRows.push(cells.map(function (c) { return c.trim(); }));
+ tableRows.push(splitTableRow(line));
continue;
} else if (inTable) {
out += flushTable();
@@ -2361,6 +2360,37 @@
return out;
}
+ function splitTableRow(line) {
+ // Split a markdown table row on cell delimiters while respecting
+ // escaped pipes (P(X\|Y)) and pipes inside inline-code spans (`a | b`).
+ var cells = [];
+ var cur = '';
+ var inCode = false;
+ for (var i = 0; i < line.length; i++) {
+ var ch = line.charAt(i);
+ if (ch === '\\' && line.charAt(i + 1) === '|') {
+ cur += '|';
+ i++;
+ continue;
+ }
+ if (ch === '`') {
+ inCode = !inCode;
+ cur += ch;
+ continue;
+ }
+ if (ch === '|' && !inCode) {
+ cells.push(cur);
+ cur = '';
+ continue;
+ }
+ cur += ch;
+ }
+ cells.push(cur);
+ if (cells.length && cells[0].trim() === '') cells.shift();
+ if (cells.length && cells[cells.length - 1].trim() === '') cells.pop();
+ return cells.map(function (c) { return c.trim(); });
+ }
+
function inlineFormat(text) {
text = text.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''');
text = text.replace(/\*\*\*(.+?)\*\*\*/g, '$1');
@@ -2462,6 +2492,62 @@
return document.documentElement.getAttribute('data-theme') === 'light' ? 'default' : 'dark';
}
+ // Lessons hard-code node fills (light pastels that vanish on the dark
+ // default theme, and dark navies that vanish in light mode). Rather than
+ // maintain a hex table, flip the lightness band while preserving hue, so
+ // color-coding survives and labels stay legible in either theme.
+ function hexToHsl(hex) {
+ var r = parseInt(hex.slice(1, 3), 16) / 255;
+ var g = parseInt(hex.slice(3, 5), 16) / 255;
+ var b = parseInt(hex.slice(5, 7), 16) / 255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b), h = 0, s = 0, l = (max + min) / 2;
+ if (max !== min) {
+ var d = max - min;
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+ if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
+ else if (max === g) h = (b - r) / d + 2;
+ else h = (r - g) / d + 4;
+ h /= 6;
+ }
+ return [h, s, l];
+ }
+
+ function hslToHex(h, s, l) {
+ function hue(p, q, t) {
+ if (t < 0) t += 1;
+ if (t > 1) t -= 1;
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
+ if (t < 1 / 2) return q;
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
+ return p;
+ }
+ var r, g, b;
+ if (s === 0) {
+ r = g = b = l;
+ } else {
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ var p = 2 * l - q;
+ r = hue(p, q, h + 1 / 3);
+ g = hue(p, q, h);
+ b = hue(p, q, h - 1 / 3);
+ }
+ function c(x) {
+ x = Math.round(Math.max(0, Math.min(1, x)) * 255);
+ return ('0' + x.toString(16)).slice(-2);
+ }
+ return '#' + c(r) + c(g) + c(b);
+ }
+
+ function mermaidPreprocess(def) {
+ var dark = mermaidTheme() === 'dark';
+ return def.replace(/fill\s*:\s*(#[0-9a-fA-F]{6})/g, function (m, hex) {
+ var hsl = hexToHsl(hex.toLowerCase());
+ if (dark && hsl[2] > 0.65) return 'fill:' + hslToHex(hsl[0], hsl[1], 0.26);
+ if (!dark && hsl[2] < 0.30) return 'fill:' + hslToHex(hsl[0], Math.min(hsl[1], 0.5), 0.86);
+ return m;
+ });
+ }
+
function updateMermaidThemeAndRerender() {
if (!window._mermaidReady) return;
try {
@@ -2486,7 +2572,7 @@
if (!idx) return;
var target = document.getElementById('mermaid-render-' + idx);
if (!target) return;
- var def = pre.textContent;
+ var def = mermaidPreprocess(pre.textContent);
target.innerHTML = 'Rendering diagram...
';
var token = ++mermaidRenderSeq;
@@ -2598,7 +2684,7 @@
var pre = document.getElementById('mermaid-' + openMermaidIndex);
if (!pre) return;
- var def = pre.textContent;
+ var def = mermaidPreprocess(pre.textContent);
center.innerHTML = 'Rendering diagram...
';
var token = ++mermaidRenderSeq;