function escapeHtml(value) {
return String(value)
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """);
}
function slide(body, { layout, className, cue } = {}) {
const lines = ["---"];
if (layout || className) {
if (layout) lines.push("layout: " + layout);
if (className) lines.push("class: " + className);
lines.push("---");
}
lines.push("", body.trim(), "");
if (cue) lines.push("", "");
return lines.join("\n");
}
function frontmatter(lesson, chapterLesson, title, subtitle, minutes, body) {
const lessonNo = String(lesson.number).padStart(2, "0");
return [
"---",
"theme: seriph",
"title: " + JSON.stringify("Chapter 1 · Lesson " + chapterLesson + " — " + title),
"info: " + JSON.stringify("English video course for AI Agents in Depth"),
"author: Bojie Li",
"transition: slide-left",
"mdc: true",
"lineNumbers: false",
"monaco: false",
"aspectRatio: 16/9",
"canvasWidth: 980",
"layout: cover",
"class: chapter-formula-cover",
"---",
"",
body.trim(),
"",
'
",
"",
"",
""
].join("\n");
}
function renderLessonOne(lesson) {
const deck = [];
deck.push(frontmatter(
lesson,
1,
"What Turns an LLM into an Agent?",
"Reasoning engine + working context + action interfaces",
18,
String.raw`
BUILD · CHAPTER 1 · AGENT FUNDAMENTALS
# What Turns an LLM into an Agent?
LLMReasoning engineUnderstand · plan · decide
+
ContextWorking setObserve · remember · retrieve
+
ToolsAction interfacesSearch · execute · communicate
Agent = Reasoning Engine + Working Context + Action Interfaces
`
));
deck.push(slide(String.raw`
# You Have Already Used an AI Agent
Chapter 1 begins with products that have crossed the boundary from answering to acting.
| Product | What it observes | What it does | How it adapts |
| Cursor | Requirements, codebase, terminal | Searches, edits, runs tests | Debugs until tests pass |
| Deep Research | Web, papers, local files | Searches, reads, synthesizes | Changes the research direction |
| Manus | Browser, files, screen | Clicks, types, executes code | Replans from interface feedback |
| Doubao | Phone screen and apps | Opens, swipes, types, confirms | Responds to the app state |
| Pine AI | Accounts, bills, provider knowledge | Calls, emails, negotiates | Adjusts strategy during the task |
Shared trait: they plan execution steps, call the tools a task requires, and revise their strategy as results arrive.
`, {
className: "chapter-dense",
cue: "Use the products to establish the behavioral shift described in the chapter opening."
}));
deck.push(slide(String.raw`
# One Formula, Three Levels of Description
| Intuition | Agent component | RL term (optional) | Responsibility |
| Reasoning engine | LLM | Policy | Given current information, choose what to do next. |
| Working context | Context | Observation space | Everything the Agent can observe, read, remember, and retrieve. |
| Action interfaces | Tools | Action space | Everything the Agent can do—from messages and APIs to code and GUI control. |
The minimal system: LLM + context + tools is enough to demonstrate an Agent loop.
The production question: later in the chapter, Harness Engineering adds constraints, verification, and correction.
`, {
className: "chapter-dense",
cue: "Define the three terms broadly, then mention that the RL column is only a vocabulary bridge."
}));
deck.push(slide(String.raw`
# Observation + Action Spaces Are the Agent's ISA
Hennessy and Patterson use the instruction set architecture as the interface between software and hardware. Chapter 1 applies the same idea to Agents.
External worldWeb · files · apps · people
Observation space→
LLMReasons over what enters context
Action space→
External worldChanged by tool execution
Outside the observation space: information effectively does not exist for the model.
Outside the action space: the model can recommend an operation, but it cannot perform it.
With the model held constant, expanding the right context or tool can make a previously unsolvable task solvable—without retraining.
`, {
className: "chapter-dense",
cue: "Trace the interface in both directions and emphasize the held-constant-model condition."
}));
deck.push(slide(String.raw`
# Generality Often Comes from Expanding the Interface Boundary
Manus: unite previously separate spaces
- Deep Research: the web enlarges observation.
- Coding: files and code execution enlarge action.
- Computer Use: screen perception and clicking enter both spaces.
Its generality did not come merely from swapping in a stronger model; it took the union of three earlier Agent categories.
OpenClaw: extend into the user's digital life
- Messaging channels make the Agent reachable from almost anywhere.
- A local-first Gateway reaches authorized local files and cloud applications.
- Plugins and Skills enlarge the action interface on demand.
The product boundary moves outward—but authorization, relevance, and verification must move with it.
Expansion is not “include everything.” Irrelevant context adds noise; too many tools increase selection cost and security risk. Useful expansion is on-demand, relevant, and controlled.
`, {
className: "chapter-dense",
cue: "Use Manus and OpenClaw exactly as the chapter uses them: as interface-expansion examples."
}));
deck.push(slide(String.raw`
# Five Agent Products, Compared on the Same Three Dimensions
| Agent type | Working context | Action interfaces | Execution strategy |
| Coding | Requirements, repository, terminal | Search, read/write files, commands | Understand → edit → test → debug |
| Search | Web, academic databases, local files | Queries, web reading, synthesis | Iteratively deepen and redirect research |
| Computer control | Screen, browser, file system | Click, type, scroll, screenshot, code | Observe interface → act → verify |
| Phone assistant | Phone screen, installed applications | Click, swipe, type, open apps | Understand intent → operate → confirm |
| Personal task | Accounts, bills, provider knowledge | Calls, email, forms, user confirmation | Gather → plan → contact → negotiate → report |
Open-ended actionGenerate language and code—not select only from fixed buttons.
Internal reasoningPlan before changing the environment.
Continuous interactionUse environmental feedback to choose the next step.
`, {
className: "chapter-dense",
cue: "Compare products by architecture rather than by brand or feature list."
}));
deck.push(slide(String.raw`
# Tools Are More Than Callable APIs
1 · Perception
Bring information into the Agent: search, files, APIs, databases.
2 · Execution
Change external systems: code, files, commands, service APIs.
3 · Collaboration
Delegate to sub-agents, request human confirmation, coordinate work.
4 · Event triggers
Email, schedules, and Webhooks activate the Agent; the Agent does not call them.
5 · User communication
Report progress or ask questions by message, voice, or email.
Tool quality defines what the Agent can accomplish reliably: vague interfaces cause misuse, weak error handling causes stalls, and broad permissions turn mistakes into irreversible actions.
`, {
className: "chapter-dense",
cue: "Preserve the chapter's broad definition of tools, especially event triggers and communication channels."
}));
deck.push(slide(String.raw`
# Tool Calling Is a Four-Step Context Update
1 · Declare the interface
{
"name": "get_weather",
"parameters": {"city": "string"}
}
2 · The model decides
{
"tool_calls": [{
"name": "get_weather",
"arguments": {"city": "Beijing"}
}]
}
3 · Execute and append the result
{
"role": "tool",
"tool_call_id": "call_1",
"content": "{\"temp\":28,\"sky\":\"clear\"}"
}
4 · Decide again from the new context
{
"role": "assistant",
"content": "Today in Beijing: 28°C, sunny."
}
Division of responsibility: the developer declares and executes tools; the model decides whether to call one, which one, and with what arguments.
`, {
className: "chapter-dense",
cue: "Walk through the API sequence and point out that the tool result becomes the next observation."
}));
deck.push(slide(String.raw`
# General Tools Compose; Specialized Tools Constrain
General-purpose foundations
- A calculator is enough for basic arithmetic.
- A constrained Python interpreter combines spreadsheet reading, cleaning, statistics, and plotting.
- A controlled working directory preserves plans, logs, intermediate results, and artifacts across long tasks.
Use for composition and exploration
Specialized high-risk operations
- Payments, deletion, email, and production deployment need explicit parameters.
- Restrict permissions and make the complete operation auditable.
- Add preview and human confirmation when an action is sensitive or irreversible.
Use to enforce business rules
Code sandbox minimums: network disabled by default; authorized working directory only; path-traversal prevention; execution-time, CPU, memory, storage, file-type, and output limits.
`, {
className: "chapter-dense",
cue: "Present generality and safety as a design trade-off, not as competing ideologies."
}));
deck.push(slide(String.raw`
# The LLM Supplies Reasoning Before It Supplies Action
The reasoning engine must infer intent, decompose a vague task, and repeatedly decide what to do next, whether to call a tool, and which arguments to use.
Zero-shot generalization
Solve a task with no demonstrations by recombining knowledge and reasoning patterns acquired during pre-training.
Example: produce a reasonable poem about quantum physics without being trained on that exact request.
Few-shot adaptation
Infer a new task pattern from two or three examples placed in the current context.
Example: learn a new user-comment → sentiment-label format from a handful of demonstrations.
Why this matters for Agents: the next action is not blind trial and error. The model draws on learned causal relationships, decomposition strategies, and world knowledge before acting.
`, {
className: "chapter-dense",
cue: "Explain zero-shot and few-shot as sources of runtime adaptability, not as separate Agent components."
}));
deck.push(slide(String.raw`
# “Model as Agent” Internalizes the Decision Policy—not the Tools
What post-training can write into weights
- When a tool call is useful.
- Which tool to choose.
- What arguments to pass.
- Whether to continue after a result.
- How to chain many calls coherently.
What remains outside the model
- The search engine and code sandbox.
- Tool declarations and provider infrastructure.
- Execution, permissions, and returned results.
- The server-side or client-side orchestration loop.
The orchestration loop has not disappeared: decision-making may move into the model while execution moves to the API server.
Chapter 1 clarification prompted by GitHub Issue #30.
`, {
className: "chapter-dense",
cue: "Make the policy-versus-execution distinction explicit; it is a central correction in the chapter."
}));
deck.push(slide(String.raw`
# Agents Learn on Three Timescales
Contextual adaptationInference-time, immediate, temporary, bounded by the context window.
Externalized learningKnowledge, prompts, Skills, programs, and Harnesses persist across tasks and remain auditable.
Parameter updatesTraining-time, costly, persistent, useful for high-dimensional capabilities and implicit policies.
Pragmatic Bitter Lesson: models will absorb parts of today’s Harness, but training moves more slowly than real business requirements. The Harness covers the current capability boundary and moves when that boundary moves.
`, {
className: "chapter-dense",
cue: "Compare persistence, update cost, and expressiveness; do not present the paths as mutually exclusive."
}));
deck.push(slide(String.raw`
# Experiment 1-2: Can Kimi K3 Sustain Native Tool Use?
Canonical task
Verify ASEAN membership and the legal status of Jakarta versus Nusantara from official sources. Search once, inspect what evidence is missing, then perform distinct follow-up searches.
Exact provider route
- Fetch Moonshot’s authoritative
web_search declaration.
- Kimi decides when and how to call it.
- Each call runs through a Formula Fiber.
- The result returns as the next observation.
Acceptance requires real provider receipts: direct Moonshot API, exact kimi-k3 model, multiple distinct successful Fibers, sequential search rounds, reasoning, final answer, retrieval date, and official-source links.
`, {
className: "chapter-dense",
cue: "State the task and acceptance criteria before switching to the terminal."
}));
deck.push(slide(String.raw`
LIVE DEMO · EXPERIMENT 1-2 · REAL API
# Switching to the terminal
~~~bash
$ uv run --extra ch1 python chapter1/web-search-agent/run_experiment_1_2.py --attempts 1 --timeout 120
~~~
Watch the policySearch queries change as missing evidence becomes visible.
Watch the interfaceEvery action is a standard web_search call executed by a Formula Fiber.
Watch the receiptsResponse IDs, Fiber IDs, sources, token usage, and acceptance checks are retained.
Requires MOONSHOT_API_KEY. If the provider is unavailable during recording, inspect the accepted credential-free artifact on the next slide and label it retained evidence.
`, {
className: "course-terminal chapter-terminal",
cue: "Run one canonical attempt. Narrate why each follow-up search occurs; do not narrate every token."
}));
deck.push(slide(String.raw`
# What the Accepted Run Actually Demonstrated
5reasoning iterations
15successful Formula Fibers
58,123total tokens
29,952cached prompt tokens
Observed in retained real-API evidence
- Different searches occurred over multiple sequential rounds.
- Every model action matched a provider-side Fiber request.
- The final answer cited ASEAN and Indonesian official sources.
- All acceptance checks passed on 2026-07-29.
What this does—and does not—show
- Shows: the model controls a long search policy and revises it from observations.
- Does not show: that the search engine or execution infrastructure lives in the weights.
- Cost: autonomy can require many calls and a large cumulative context.
Evidence: chapter1/web-search-agent/validation/latest.json · evidence mode: real_api
`, {
className: "chapter-dense",
cue: "Separate the accepted evidence from the architectural interpretation."
}));
deck.push(slide(String.raw`
# The Capability Boundary Is Often the Interface Boundary
Reasoning engine
The LLM supplies world knowledge, planning, judgment, zero-shot generalization, and a learned tool-use policy.
Working context
The observation space determines which task state, evidence, memory, and environmental feedback can influence a decision.
Action interfaces
Tools determine which operations can affect the world; broader interfaces require stronger permissions and verification.
When an Agent cannot solve a task, first locate the missing capability: model policy, observable information, or executable action.
`, {
className: "chapter-dense",
cue: "Close with the chapter's systems-engineering lever, then bridge to the working context in Lesson 2."
}));
return { markdown: deck.join("\n"), slideCount: deck.length };
}
function renderLessonTwo(lesson) {
const deck = [];
deck.push(frontmatter(
lesson,
2,
"What Is Inside an Agent's Context?",
"Static prefix + dynamic trajectory",
19,
String.raw`
BUILD · CHAPTER 1 · AGENT FUNDAMENTALS
# What Is Inside an Agent's Context?
Static prefixSystem promptTool definitions
+
TrajectoryUser messagesAssistant messagesTool results
Every model call sees the prefix plus the trajectory accumulated so far.
`
));
deck.push(slide(String.raw`
# Context Is the Agent's Working Set—not Its Entire Memory
Context is the information available to the Agent at one decision point: the task instructions, relevant references, earlier correspondence, current state, and the latest tool observations.
What enters the working set
- The system prompt and stable rules.
- Definitions of tools currently available.
- User input and retrieved external knowledge.
- Earlier assistant decisions and actions.
- Results returned by the environment.
What the model cannot use directly
- State retained only inside application code.
- A tool implementation whose definition was not supplied.
- An execution result that was never appended.
- A previous turn removed during compression.
- Relevant knowledge that retrieval did not surface.
The Agent can decide only from information present at decision time—even if the missing fact exists elsewhere in the system.
`, {
className: "chapter-dense",
cue: "Distinguish persistent storage from the smaller working set exposed on the current call."
}));
deck.push(slide(String.raw`
# The API-Level Context Has Five Components
| Component | Who supplies it | What it carries | Failure if absent |
| System prompt | Developer / framework | Identity, permissions, conduct, memory, injected state | No stable role or behavioral boundary |
| Tool definitions | Developer / provider | Names, descriptions, parameters, formats | The model cannot recognize or call the tool |
| User messages | User + retrieval layer | Request and dynamically retrieved knowledge | The current goal or required evidence is missing |
| Assistant messages | Model | Reasoning, user-facing content, tool calls | Prior decisions and proposed actions disappear |
| Tool results | Environment / Harness | Execution feedback and new observations | The Agent acts without knowing what happened |
Experiment 1-1 tests four removals. The system prompt is exempt because without a basic identity definition the test no longer represents the same Agent.
`, {
className: "chapter-dense",
cue: "Use the failure column to make each component operational rather than definitional."
}));
deck.push(slide(String.raw`
# Static Prefix + Dynamic Trajectory
Static prefix
System prompt
Tool definitions
Stable across calls; cache-friendly
+
Trajectory
User → assistant reasoning/tool calls → tool results → assistant…
Grows after every interaction with the environment
=
Next LLM input
Everything visible at this decision point
Why retain the trajectory? It records completed work, unresolved questions, decisions, tool arguments, observations, and progress.
Why not retain everything forever? The prompt grows, cost rises, irrelevant history competes for attention, and retrieval becomes harder.
`, {
className: "chapter-dense",
cue: "Establish the exact equation that the next slides and experiment will probe."
}));
deck.push(slide(String.raw`
# An Assistant Message Can Carry Thought, Speech, and Action
{
"role": "assistant",
"reasoning": "Need EUR, GBP, and JPY rates…",
"content": "",
"tool_calls": [
{"name": "convert_currency",
"arguments": {"amount": 2100000,
"from": "EUR", "to": "USD"}}
]
}
Reasoning
Preserves why the previous decision was made and supports coherence across steps.
Content
Communicates with the user; often empty while the Agent is still acting.
Tool calls
Structured proposals for changing or observing the external environment.
The tool result is a separate message. The framework executes the proposal and appends the observation under the matching tool-call ID.
`, {
className: "chapter-dense",
cue: "Point out that the three fields need not appear together on every assistant response."
}));
deck.push(slide(String.raw`
# Experiment 1-1 Removes One Information Channel at a Time
Canonical task
Convert quarterly revenue in USD, EUR, GBP, and JPY into USD, then calculate the annual total and quarterly average without estimating exchange rates.
Control
The full arm keeps all five components and should complete in a small number of iterations.
Ablations
Remove tool definitions, tool results, retained reasoning, or message history while holding the task and model constant.
Ablation is diagnostic: different missing components should create different, observable failure signatures.
`, {
className: "chapter-dense",
cue: "Define the controlled comparison before showing expected or observed behavior."
}));
deck.push(slide(String.raw`
# What Should Break When Each Component Disappears?
| Arm | Actual request change | Predicted signature from the chapter | Disconfirming observation |
| Full | No removal | Correct answer with a coherent sequence | Wrong answer, unnecessary repetition, or no completion |
| No tool definitions | Omit tools and tool_choice | No tool action is possible | The model successfully invokes an undeclared tool |
| No tool results | Replace every observation with a hidden marker | Repeated calls or unsupported conclusions | Correct answer derived only from hidden observations |
| No reasoning | Remove prior reasoning from history | Less coherent or contradictory decisions | No measurable degradation on the tested task |
| No history | Send only system + current user each round | Restarting and repeated operations | The Agent remembers completed work anyway |
Important: the runner verifies the request contract itself—what the provider actually received—not merely the CLI mode name.
`, {
className: "chapter-dense",
cue: "State predictions in falsifiable form; the no-reasoning result will matter later."
}));
deck.push(slide(String.raw`
# ReAct Connects Context, Model, and Tools
Reason
Given the complete current context, decide what information or action is needed next.
Act
Emit a structured tool call; the Harness executes it outside the model.
Observe
Append the result, creating a richer context for the next call.
A loop also needs exit conditions: task complete, final-output tool called, no tool call, unrecoverable error, or maximum rounds reached.
`, {
className: "chapter-dense",
cue: "Explain why the name ReAct omits observation even though observation is operationally indispensable."
}));
deck.push(slide(String.raw`
# Every Round Sees the Entire Trajectory So Far
Round 1Reason about missing exchange rates; call currency tools in parallel.
Round 2Observe conversions; call the code interpreter to aggregate.
Round 3Observe the calculation; return total and quarterly average.
The trajectory is the dynamic part of the next prompt, not a log consulted after execution.
`, {
className: "chapter-dense",
cue: "Trace one item from action to observation to the next decision."
}));
deck.push(slide(String.raw`
# The Revenue Task Completes in 3 Iterations and 4 Tool Calls
trajectory = [
user("Q1 $2.5M, Q2 €2.1M, Q3 £1.8M, Q4 ¥380M"),
assistant(
reasoning="Convert non-USD quarters first",
tool_calls=[eur_to_usd, gbp_to_usd, jpy_to_usd]),
tool(eur_result), tool(gbp_result), tool(jpy_result),
assistant(
reasoning="Aggregate verified USD values",
tool_calls=[code_interpreter(total_and_average)]),
tool("Total $9,602,895.73; average $2,400,723.93"),
assistant(content="FINAL ANSWER …"),
]
Why accumulation matters
- The second call knows which conversions were requested.
- It sees the returned rates rather than inventing them.
- The third call sees the calculation result and knows the task is complete.
- Structured roles keep proposals and observations distinguishable.
Without the accumulated trajectory, each round can look like the beginning of the task.
`, {
className: "chapter-dense",
cue: "Connect the pseudocode to the previous diagram; do not dwell on syntax."
}));
deck.push(slide(String.raw`
# A Trajectory Is Both Runtime State and Learning Evidence
During the current task
- Preserves progress and unresolved work.
- Prevents redundant actions.
- Exposes why a decision followed an observation.
- Makes execution interpretable and debuggable.
Across many tasks
- Reveals recurring behavior and failure patterns.
- Identifies better decision paths and tool interfaces.
- Can be distilled into knowledge or external artifacts.
- Can provide data for reinforcement learning.
The cost is cumulative. Every call receives the growing trajectory; long tasks therefore create token, latency, attention, and compression problems that Chapter 2 addresses directly.
`, {
className: "chapter-dense",
cue: "Use this slide to bridge runtime context to later chapters on compression and learning from experience."
}));
deck.push(slide(String.raw`
# Live Comparison: Control, Ablation, and Retained Five-Arm Evidence
1-1A · 3 minRun two arms live
Compare the full context with no_history on one canonical case.
- Count iterations and tool actions.
- Watch whether the same calls repeat.
- Check whether a final numerical answer appears.
1-1B · 1 minInspect the accepted five-arm artifact
Use the retained direct-API run to compare all arms—including the negative no-reasoning result.
- Verify evidence mode and acceptance.
- Distinguish execution success from hypothesis support.
Do not overclaim: the live two-arm run is a focused comparison. The complete five-arm conclusion comes from the linked accepted artifact unless all five arms are rerun during recording.
`, {
className: "chapter-dense",
cue: "Set expectations before the terminal: one live comparison plus one retained-evidence inspection."
}));
deck.push(slide(String.raw`
LIVE DEMO · EXPERIMENT 1-1
# Switching to the terminal
~~~bash
$ uv run --extra ch1 python chapter1/context/main.py --mode ablation --provider kimi --ablation-modes full no_history --cases 1 --output /tmp/ch1-context-live.json
$ jq '{evidence_mode, accepted:.analysis.experiment_execution_accepted, claims:.analysis.manuscript_behavior_claims, arms:[.arms[]|{mode,iterations,actions:.behavior.tool_action_count,repeated:.behavior.has_repeated_tool_action,correct:.behavior.canonical_answer_correct}]}' chapter1/context/validation/latest.json
~~~
Control3 iterations, 4 actions, correct total in the accepted run.
No historyIteration ceiling and repeated actions are the predicted signature.
Negative resultNo-reasoning remained correct in the accepted run.
The live API command requires MOONSHOT_API_KEY. The second command reads credential-free retained evidence and is safe to use if the provider is unavailable.
`, {
className: "course-terminal chapter-terminal",
cue: "Run the two-arm comparison, then use jq to make all five retained outcomes visible."
}));
deck.push(slide(String.raw`
# The Real Ablation Result Is More Useful Than a Perfect Story
| Arm | Iterations | Tool actions | Repeated? | Correct answer? | Interpretation |
| Full | 3 | 4 | No | Yes | Control completed normally. |
| No history | 5, ceiling | 15 | Yes · 12 repeats | No answer | Lost progress and restarted work. |
| No reasoning | 3 | 4 | No | Yes | Expected degradation was not reproduced. |
| No tool definitions | 1 | 0 | No | No | Model declined to invent exchange rates. |
| No tool results | 5 | 7 | Yes · 3 repeats | No | Calls ran, but observations were hidden. |
Execution accepted: all five direct-provider request contracts were verified and the intended ablations were actually applied.
Manuscript hypothesis partially supported: three predicted failure mechanisms reproduced; the no-reasoning claim did not on this task and model.
Evidence: chapter1/context/validation/latest.json · 31,870 total tokens · created 2026-07-29
`, {
className: "chapter-dense",
cue: "Lead with the negative result; it is stronger evidence of an honest experiment than a forced confirmation."
}));
deck.push(slide(String.raw`
# Context Determines What the Agent Knows at Decision Time
Definitions enable action
Without the tool schema, the model cannot recognize or call the action interface—even when it understands the task.
Results close the loop
Without observations, execution does not become evidence; the Agent repeats calls or refuses to invent a result.
History preserves progress
Without earlier messages, each decision loses completed work and can restart from the original request.
Before compressing or discarding context, identify the state carried by each message and the observable failure caused by losing it.
`, {
className: "chapter-dense",
cue: "Close on the experimentally supported components, then hand the compression problem to Chapter 2."
}));
return { markdown: deck.join("\n"), slideCount: deck.length };
}
export const chapter1PilotFigures = new Set([
"fig1-1.svg",
"fig1-2.svg",
"fig1-3.svg",
"fig1-4.svg",
"fig1-5.svg"
]);
export function chapter1PilotSlideCount(number) {
if (number === 2) return 16;
if (number === 3) return 15;
return null;
}
export function renderChapter1Pilot(lesson) {
if (lesson.number === 2) return renderLessonOne(lesson);
if (lesson.number === 3) return renderLessonTwo(lesson);
return null;
}