Skip to content

Commit b5ea64a

Browse files
alfredangclaude
andcommitted
feat(rag7b): fix CX Agent + Pinecone flows (Gemini 3072-d, POST webhook, whole-brochure chunks); deck v43, LG v6.2
- Activity 7b flows updated from alfredang/n8n-ragdemo2: CX Agent webhook now POST + Respond to Webhook with a Pinecone retriever tool and Gemini chat model; Pinecone ingestion embeds with gemini-embedding-001 (3072-dim index) using one-brochure-one-chunk splitting - Learner Guides (lab 7b + course LG v6.2) document the matching upload/retrieval namespace rule and the whole-brochure chunking rationale; new workflow screenshots - Slide deck v43: 3-column n8n account login table (workspace URL / login / password) and updated Activity 7b slides - Versioning rule (bump version + version-control record on every update) added to WSQ courseware skills - Assessment folder excluded from the repo (confidential); Powered-by footer added to lab websites Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent f27b0b7 commit b5ea64a

30 files changed

Lines changed: 476 additions & 396 deletions

.claude/skills/tertiary-course-slides/SKILL.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,13 @@ Every generated document/deck MUST include:
3535
- **Brand colours**: blue `#1F6FEB`, teal `#10B981`, ink `#161B26`, grey `#5B6372`.
3636

3737
The reusable helper `prodoc.py` implements the cover page, version-control table, TOC field, page numbering and copyright footer — import it and call `add_cover_page`, `add_version_control`, `add_toc`, `add_page_numbers`, `enable_update_fields`, `style_headings`.
38+
39+
## Versioning rule (MANDATORY — every update)
40+
41+
Every content update to a courseware artifact MUST, in the same change:
42+
43+
1. **Bump the version number** (and the version date) in the generator/template — e.g. `VERSION="vNN"` for slide decks (the version is also part of the output filename), `VERSION = "N.N"` plus a new `VERSIONS` entry for DOCX documents.
44+
2. **Document the change in the Document Version Control Record** — add a row (Version Number | Effective Date of Release | Summary of Included Changes | Author) wherever the document carries one (Learner Guide / Lesson Plan). For slide decks the bumped version must appear on the cover page and in the filename.
45+
3. **Regenerate the outputs**, remove (`git rm`) the superseded versioned files, and update any references to the versioned filename (README, slides that cite the document, etc.).
46+
47+
Never regenerate an artifact with content changes while keeping the old version number.

.claude/skills/tertiary-course-slides/make_slides.py

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
AMBER=RGBColor(0xF5,0x9E,0x0B); INK=RGBColor(0x16,0x1B,0x26); GREY=RGBColor(0x5B,0x63,0x72)
1616
LIGHT=RGBColor(0xF5,0xF8,0xFC); WHITE=RGBColor(0xFF,0xFF,0xFF); LINE=RGBColor(0xE2,0xE8,0xF0)
1717
VIOLET=RGBColor(0x7C,0x3A,0xED)
18-
VERSION="v42"; VERSION_DATE="1 July 2026"
18+
VERSION="v43"; VERSION_DATE="3 July 2026"
1919
# ─── EDIT PER COURSE ─────────────────────────────────────────────
2020
TITLE = "Agentic AI Automation with n8n" # <<Course Title>>
2121
COURSE_CODE = "TGS-2023035977" # <<Course Code, e.g. TGS-XXXXXXXXXX>>
@@ -276,26 +276,23 @@ def brk(kind,dur,color):
276276
"See labs/n8n-installation/docker-compose.yml in the course repo."],kicker="GET READY")
277277
# --- n8n Cloud Account Login Details ---
278278
_s=slide(); head(_s,"n8n Account Login Details",kicker="YOUR LOGIN · CLOUD INSTANCE")
279-
rect(_s,Inches(0.85),Inches(1.85),Inches(11.6),Inches(0.5),RGBColor(0xEB,0xF4,0xFF))
280-
txt(_s,Inches(1.05),Inches(1.89),Inches(2.2),Inches(0.44),[[("Workspace URL",13,BLUE,True)]],anchor=MSO_ANCHOR.MIDDLE)
281-
txt(_s,Inches(3.3),Inches(1.89),Inches(9.0),Inches(0.44),[[("http://n8n.srv923061.hstgr.cloud:5678",14,INK,False)]],anchor=MSO_ANCHOR.MIDDLE)
282-
rect(_s,Inches(0.85),Inches(2.43),Inches(11.6),Inches(0.5),RGBColor(0xEB,0xF4,0xFF))
283-
txt(_s,Inches(1.05),Inches(2.47),Inches(2.2),Inches(0.44),[[("Password",13,BLUE,True)]],anchor=MSO_ANCHOR.MIDDLE)
284-
txt(_s,Inches(3.3),Inches(2.47),Inches(3.5),Inches(0.44),[[("Tertiary@888",14,TEAL,True)]],anchor=MSO_ANCHOR.MIDDLE)
285-
txt(_s,Inches(6.9),Inches(2.47),Inches(4.8),Inches(0.44),[[("(same for all accounts)",12,GREY,False)]],anchor=MSO_ANCHOR.MIDDLE)
286-
_RH=Inches(0.355); _TY=Inches(3.08)
287-
for _ci in range(2):
288-
_bx=Inches(0.85)+_ci*Inches(6.0); _cw=Inches(5.7); _nw=Inches(0.55)
289-
_ew=_cw-_nw-Inches(0.1)
290-
rect(_s,_bx,_TY,_cw,_RH,BLUE)
291-
txt(_s,_bx+Inches(0.05),_TY,_nw,_RH,[[("No.",11,WHITE,True)]],align=PP_ALIGN.CENTER,anchor=MSO_ANCHOR.MIDDLE)
292-
txt(_s,_bx+_nw+Inches(0.1),_TY,_ew,_RH,[[("Email",11,WHITE,True)]],anchor=MSO_ANCHOR.MIDDLE)
293-
for _ri in range(10):
294-
_no=_ci*10+_ri+1; _em=f"n8n{1000+_no:04d}@tertiaryinfotech.com"
295-
_ry=_TY+_RH*(_ri+1)
296-
rect(_s,_bx,_ry,_cw,_RH,LIGHT if _ri%2==0 else WHITE,line=LINE)
297-
txt(_s,_bx+Inches(0.05),_ry,_nw,_RH,[[(str(_no),11,INK,True)]],align=PP_ALIGN.CENTER,anchor=MSO_ANCHOR.MIDDLE)
298-
txt(_s,_bx+_nw+Inches(0.1),_ry,_ew,_RH,[[(_em,11,INK,False)]],anchor=MSO_ANCHOR.MIDDLE)
279+
_TY=Inches(1.78); _RH=Inches(0.247); _bx=Inches(0.85)
280+
_wNo=Inches(0.55); _wUrl=Inches(4.95); _wEm=Inches(4.35); _wPw=Inches(1.75)
281+
_cols=[(_bx,_wNo,"No.",PP_ALIGN.CENTER),
282+
(_bx+_wNo+Inches(0.1),_wUrl-Inches(0.1),"Workspace URL",PP_ALIGN.LEFT),
283+
(_bx+_wNo+_wUrl+Inches(0.1),_wEm-Inches(0.1),"Login (Email)",PP_ALIGN.LEFT),
284+
(_bx+_wNo+_wUrl+_wEm+Inches(0.1),_wPw-Inches(0.1),"Password",PP_ALIGN.LEFT)]
285+
rect(_s,_bx,_TY,_wNo+_wUrl+_wEm+_wPw,_RH,BLUE)
286+
for _cx,_cw2,_lbl,_al in _cols:
287+
txt(_s,_cx,_TY,_cw2,_RH,[[(_lbl,11,WHITE,True)]],align=_al,anchor=MSO_ANCHOR.MIDDLE)
288+
for _ri in range(20):
289+
_no=_ri+1; _acct=f"n8n{1000+_no:04d}"
290+
_ry=_TY+_RH*(_ri+1)
291+
rect(_s,_bx,_ry,_wNo+_wUrl+_wEm+_wPw,_RH,LIGHT if _ri%2==0 else WHITE,line=LINE)
292+
for (_cx,_cw2,_lbl,_al),(_val,_c,_b) in zip(_cols,
293+
[(str(_no),INK,True),(f"https://{_acct}.app.n8n.cloud/signin",BLUE,False),
294+
(f"{_acct}@tertiaryinfotech.com",INK,False),("Tertiary@888",TEAL,False)]):
295+
txt(_s,_cx,_ry,_cw2,_RH,[[(_val,10,_c,_b)]],align=_al,anchor=MSO_ANCHOR.MIDDLE)
299296
footer(_s)
300297
content("Credential Setup",[
301298
"Add credentials once under Credentials → Add credential.",
@@ -688,47 +685,47 @@ def activity_block(a):
688685
(TEAL,"Supabase (pgvector)",["Postgres + vector extension","SQL table + match function","Self-host or hosted; great if you already use Postgres"]),
689686
(BLUE,"Pinecone",["Fully managed SaaS","Just create an index (no schema)","Zero-ops, serverless, scales fast"]),
690687
(VIOLET,"Qdrant",["Open-source vector DB","Run via Docker or Qdrant Cloud","Full control / self-hosted"])],kicker="ACT 7b · CHOOSE ONE")
691-
content("One Embedding Model, One Dimension",[
692-
"All three stores ingest the same 20 brochures using OpenAI text-embedding-3-small.",
693-
"That model outputs 1536-dimension vectors — the store's dimension MUST equal 1536.",
694-
"Change the embedding model and the dimension changes too (e.g. -3-large = 3072).",
688+
content("Embedding Model Sets the Dimension",[
689+
"Supabase & Qdrant flows embed with OpenAI text-embedding-3-small → 1536-dim vectors.",
690+
"The Pinecone flow & CX Agent embed with Google Gemini gemini-embedding-001 → 3072-dim.",
691+
"The store's dimension MUST equal the embedding model's output dimension.",
695692
"Mismatched dimensions are the #1 cause of failed inserts."],kicker="DIMENSION RULE")
696693
website_slide("Pinecone — Example Managed Store",IMG("courseware/assets/site-pinecone.png"),
697-
["Pinecone is a managed (cloud) vector database for RAG.","Free 'Starter' tier is enough for this lab.","Create an index: Dimensions = 1536, Metric = cosine."],
694+
["Pinecone is a managed (cloud) vector database for RAG.","Free 'Starter' tier is enough for this lab.","Create an index: Dimensions = 3072 (Gemini), Metric = cosine."],
698695
kicker="VECTOR DATABASE")
699696

700697
# ===== Activity 7b — Customer-support RAG agent for a training center =====
701698
activity_overview("ACT 7b","Activity 7b — Customer-Support RAG Agent (Cook & Bake Academy)",
702699
"A cooking & bakery training center's website has a support chatbot. Ingest 20 course brochures from Google Drive into a vector database, then a CX Agent answers visitor questions about course duration, fees, location and schedule — grounded in the brochures.",
703-
"Manual Trigger → Drive (list+download) → Split → Embeddings (OpenAI) → Vector Store | Website → Webhook → AI Agent + retriever → reply",
704-
"manualTrigger, googleDrive, textSplitter, embeddingsOpenAi, vectorStore (Supabase/Pinecone/Qdrant), agent, webhook, respondToWebhook",kicker=K3)
700+
"Manual Trigger → Drive (list+download) → Split → Embeddings → Vector Store | Website → Webhook (POST) → AI Agent + retriever tool → Respond to Webhook",
701+
"manualTrigger, googleDrive, textSplitter, embeddings (OpenAI/Gemini), vectorStore (Supabase/Pinecone/Qdrant), agent, lmChatGoogleGemini, webhook, respondToWebhook",kicker=K3)
705702
img_slide("Activity 7b — Ingestion Workflow",IMG("labs/activity7-rag/Activity7b-Pinecone-Upload.png"),
706-
"Ingestion pattern (shown: Pinecone) — list & download brochures → split → embed (OpenAI 1536-d) → upsert. Same flow for Supabase & Qdrant.",kicker=K3)
703+
"Ingestion pattern (shown: Pinecone) — list & download brochures → whole-brochure split (1 brochure = 1 chunk) → embed (Gemini 3072-d) → upsert. Supabase & Qdrant use OpenAI 1536-d.",kicker=K3)
707704
img_slide("Activity 7b — CX Agent Workflow",IMG("labs/activity7-rag/Activity7b-CX-Agent.png"),
708-
"The answering agent: website webhook → retrieve from the vector store → respond to the chat widget",kicker=K3)
705+
"The answering agent: website webhook (POST) → AI Agent with Pinecone retriever tool + Gemini chat model → respond to the chat widget",kicker=K3)
709706
website_slide("Cook & Bake Academy — Support Chatbot",IMG("labs/activity7-rag/Activity7b-website.png"),
710707
["A one-page training-center site with a floating chat widget.",
711708
"Visitors ask about any course — duration, fee, location, schedule.",
712709
"Answers are grounded in the 20 ingested brochures.",
713710
"Set WEBHOOK_URL in script.js to your n8n CX Agent URL."],kicker="ACT 7b · THE WEBSITE")
714711
for i,t in enumerate([
715712
"Upload the 20 course brochures (labs/activity7-rag/brochures/) to a Google Drive folder named 'Course Brochures'; copy the folder ID from the URL.",
716-
"Choose one vector database — Supabase, Pinecone or Qdrant. All use OpenAI text-embedding-3-small (1536-dim); the store must match 1536.",
713+
"Choose one vector database — Supabase, Pinecone or Qdrant. Supabase/Qdrant use OpenAI text-embedding-3-small (1536-dim); Pinecone uses Google Gemini gemini-embedding-001 (3072-dim).",
717714
"Supabase: create a project, enable pgvector, run the SQL to create the documents table + match_documents function, then add a Supabase credential.",
718-
"Pinecone: create an index 'course-brochures' (Dimensions = 1536, Metric = cosine); add a Pinecone credential.",
715+
"Pinecone: create an index 'course-brochures' (Dimensions = 3072, Metric = cosine); add Pinecone + Google Gemini credentials. Upload & retrieval must use the SAME namespace (both default).",
719716
"Qdrant: create a cluster (Qdrant Cloud) or run via Docker; create collection 'course-brochures' (size 1536, Cosine); add a Qdrant credential.",
720-
"Import the matching ingestion workflow (Activity7b-Supabase / Pinecone / Qdrant-Upload.json). Set the Drive folder ID on 'List Brochures in Folder' and your OpenAI + Drive + DB credentials.",
721-
"Click Execute workflow — it lists, downloads, splits, embeds and upserts ~30–60 vectors. Verify the rows / vectors appear in your DB.",
722-
"Import Activity7b-CX-Agent.json. Point its retriever vector-store node at the same store you ingested into (same 1536-dim embeddings); add OpenAI + DB credentials.",
723-
"Activate and copy the Webhook production URL. Set WEBHOOK_URL in website/script.js to it.",
717+
"Import the matching ingestion workflow (Activity7b-Supabase / Pinecone / Qdrant-Upload.json). Set the Drive folder ID on 'List Brochures in Folder' and your Drive + embeddings + DB credentials.",
718+
"Click Execute workflow. Pinecone keeps 1 brochure = 1 chunk (similar brochures confuse retrieval if split) → exactly 20 vectors; Supabase/Qdrant upsert ~30–60 chunks.",
719+
"Import Activity7b-CX-Agent.json. Point its Pinecone retriever tool at the same 'course-brochures' index — same Gemini embeddings (3072-dim) and same (default) namespace.",
720+
"Activate and copy the Webhook production URL (the webhook accepts POST and replies via Respond to Webhook). Set WEBHOOK_URL in website/script.js to it.",
724721
"Open website/index.html, click the 💬 chat button, and ask 'How much is the sourdough course?'"],1):
725722
step_slide(K3,"Activity 7b — Customer-Support RAG Agent (Cook & Bake Academy)",i,10,t)
726723
test_slide("Activity 7b — Customer-Support RAG Agent (Cook & Bake Academy)","On the website chat widget ask 'How long is the French Pastry course?' or 'Where are you located?' — the chatbot answers grounded in the brochures retrieved from your vector database.",K3)
727724
content("Vector Databases — Quick Comparison",[
728725
"Supabase (pgvector): Postgres + extension · SQL table & function · self-host or hosted · best if you already use Postgres.",
729726
"Pinecone: managed SaaS · just create an index · zero-ops · scales fast.",
730727
"Qdrant: open-source · Docker or Qdrant Cloud · full control / self-hosted.",
731-
"All three store the same 1536-dim OpenAI embeddings — swap the store, keep the RAG flow."],kicker="ACT 7b · RECAP")
728+
"Match the store's dimension to the embedding model (OpenAI 1536 / Gemini 3072) — swap the store, keep the RAG flow."],kicker="ACT 7b · RECAP")
732729
brk("Lunch Break","1 hour",AMBER)
733730

734731
# ---------- TOPIC 6: SECURITY ----------

.claude/skills/tertiary-learner-guide/SKILL.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,13 @@ Every generated document/deck MUST include:
3333
- **Brand colours**: blue `#1F6FEB`, teal `#10B981`, ink `#161B26`, grey `#5B6372`.
3434

3535
The reusable helper `prodoc.py` implements the cover page, version-control table, TOC field, page numbering and copyright footer — import it and call `add_cover_page`, `add_version_control`, `add_toc`, `add_page_numbers`, `enable_update_fields`, `style_headings`.
36+
37+
## Versioning rule (MANDATORY — every update)
38+
39+
Every content update to a courseware artifact MUST, in the same change:
40+
41+
1. **Bump the version number** (and the version date) in the generator/template — e.g. `VERSION="vNN"` for slide decks (the version is also part of the output filename), `VERSION = "N.N"` plus a new `VERSIONS` entry for DOCX documents.
42+
2. **Document the change in the Document Version Control Record** — add a row (Version Number | Effective Date of Release | Summary of Included Changes | Author) wherever the document carries one (Learner Guide / Lesson Plan). For slide decks the bumped version must appear on the cover page and in the filename.
43+
3. **Regenerate the outputs**, remove (`git rm`) the superseded versioned files, and update any references to the versioned filename (README, slides that cite the document, etc.).
44+
45+
Never regenerate an artifact with content changes while keeping the old version number.

0 commit comments

Comments
 (0)