Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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?<br/>Decentralized identity (DID), E2EE, meta-protocol"]
A2A["A2A — How do agents collaborate on goals?<br/>Agent Cards, task lifecycle, streaming, negotiation"]
ACP["ACP — How do agents talk in auditable systems?<br/>Runs, trajectory metadata, session continuity"]
MCP["MCP — How does an agent use a tool?<br/>Tool discovery, execution, context sharing"]

style ANP fill:#f3e8ff,stroke:#7c3aed
style A2A fill:#dbeafe,stroke:#2563eb
Expand Down Expand Up @@ -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):
Expand Down
100 changes: 93 additions & 7 deletions site/lesson.html
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '';
Expand Down Expand Up @@ -2149,7 +2149,7 @@
for (var ri = 2; ri < tableRows.length; ri++) {
var cells = tableRows[ri];
h += '<tr>';
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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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(); });
}
Comment on lines +2363 to +2392
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Preserve \| inside inline code spans.

splitTableRow() unescapes \| before it checks whether the parser is currently inside backticks, so a cell like `\|` is rendered as `|`. That still mutates valid Markdown content in the exact case this helper is supposed to protect.

Suggested fix
       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 (!inCode && ch === '\\' && line.charAt(i + 1) === '|') {
+          cur += '|';
+          i++;
+          continue;
+        }
         if (ch === '|' && !inCode) {
           cells.push(cur);
           cur = '';
           continue;
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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 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 === '`') {
inCode = !inCode;
cur += ch;
continue;
}
if (!inCode && ch === '\\' && line.charAt(i + 1) === '|') {
cur += '|';
i++;
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(); });
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@site/lesson.html` around lines 2363 - 2392, splitTableRow currently unescapes
backslash-escaped pipes before checking inCode, so sequences like `\|` inside
backtick spans become `|`; change the logic so the handler for a backslash
followed by '|' only consumes the escape and appends '|' when not inside a code
span (i.e., check inCode before treating '\\' + '|' as an escape), and when
inCode append the raw backslash and '|' to cur; adjust the condition around the
backslash handling in function splitTableRow (variables: inCode, cur, ch)
accordingly so escaped pipes are preserved inside inline code.


function inlineFormat(text) {
text = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
text = text.replace(/\*\*\*(.+?)\*\*\*/g, '<strong><em>$1</em></strong>');
Expand Down Expand Up @@ -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 {
Expand All @@ -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 = '<div class="panel-loading">Rendering diagram...</div>';

var token = ++mermaidRenderSeq;
Expand Down Expand Up @@ -2598,7 +2684,7 @@

var pre = document.getElementById('mermaid-' + openMermaidIndex);
if (!pre) return;
var def = pre.textContent;
var def = mermaidPreprocess(pre.textContent);

center.innerHTML = '<div class="panel-loading">Rendering diagram...</div>';
var token = ++mermaidRenderSeq;
Expand Down
Loading