toga-ai 1.0.640 → 1.0.641

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,9 +5,10 @@
5
5
  | [AI-BDR Architecture](architecture.md) | **AI-BDR** is TOGA's outbound AI sales-development representative. | ai-bdr/README.md, ai-bdr/requirements.txt, ai-bdr/.env.example, ai-bdr/docs/client-onboarding-sop.md, ai-bdr/docs/vapi-firstmessage-timing-fix.md, ai-bdr/docs/vapi-inbound-callback-assistant-request.md, ai-bdr/docs/vapi-voicemail-iphone-screening.md, ai-bdr/vapi/templates/system-prompt.template.md, ai-bdr/vapi/templates/assistant.template.json, ai-bdr/prompts/archive/prompt-may-15.txt, ai-bdr/prompts/campaigns/healthcare-2026-03-18.md, ai-bdr/prompts/campaigns/healthcare-v2-2026-03-25.md, ai-bdr/scripts/update_assistant.py, ai-bdr/scripts/update_system_prompt.py, ai-bdr/scripts/update_structured_output.py, ai-bdr/scripts/update_call_summary_context.py, ai-bdr/scripts/fix_booking_guardrails.py, ai-bdr/scripts/get_assistant.py |
6
6
  | [BDR Web Funnel — Full Implementation Plan](features/bdr-web-funnel-plan.md) | > **Execution status (2026-07-16):** PLAN **Phases 0–5 are BUILT and QA'd**, Phase 6 > was **mostly already built** (the `info` contract was implemented at comm | bdr/PLAN.md, bdr/mockup/app.jsx, bdr/mockup/screens.jsx, bdr/mockup/components.jsx |
7
7
  | [Call Orchestration — PHP Worker ↔ Vapi (the integration seam)](features/call-orchestration.md) | The **PHP worker** is the orchestrator; **Vapi** is the actor. | ai-bdr/docs/client-onboarding-sop.md, ai-bdr/docs/vapi-firstmessage-timing-fix.md, ai-bdr/docs/vapi-inbound-callback-assistant-request.md, ai-bdr/docs/vapi-voicemail-iphone-screening.md, ai-bdr/scripts/update_structured_output.py |
8
- | [AI-BDR Campaign Chat — Backend Contract + Frontend Widget Handoff](features/campaign-chat-handoff.md) | The consolidated backend + frontend handoff for the **AI-BDR campaign chat** — a grounded AI-BDR chat widget for landing pages, powered by the Talos backend at | ai-bdr-campaign-handoff.md |
8
+ | [AI-BDR Campaign Chat — Backend Contract + Frontend Widget Handoff](features/campaign-chat-handoff.md) | The consolidated backend + frontend handoff for the **AI-BDR campaign chat** — a grounded AI-BDR chat widget for landing pages, powered by the Talos backend at | ai-bdr-campaign-handoff.md, bdr/src/lib/talosChat.ts |
9
+ | [Talos Chat Drawer on /landing (first campaign-chat consumer)](features/landing-chat-drawer.md) | The **right-anchored chat drawer on `/landing`**, wired to the **real** Talos campaign-chat backend at `https://api.togaiq.com`. | bdr/src/components/ChatPanel.tsx, bdr/src/components/ChatMarkdown.tsx, bdr/src/lib/talosChat.ts, bdr/src/content/security.ts, bdr/src/flow/screens/SecurityLanding.tsx, bdr/src/app/security.css, bdr/test/talosChat.test.ts, bdr/test/chatMarkdown.test.ts |
9
10
  | [Live Call Status — Vapi call API → funnel Success screen lifecycle](features/live-call-status.md) | The BDR funnel's Success screen shows the **real** state of the call it just requested — dialing / ringing / answered-and-talking / ended / not-answered — inste | bdr/src/server/vapiCall.ts, bdr/src/server/callStatus.ts, bdr/src/server/statusToken.ts, bdr/src/server/callbackService.ts, bdr/src/server/workerDialer.ts, bdr/src/lib/callStatus.ts, bdr/src/app/api/call-status/route.ts, bdr/src/app/api/call-now/route.ts, bdr/src/flow/useCallStatusViewModel.ts, bdr/src/flow/callStatusApi.ts, bdr/src/flow/screens/Success.tsx, bdr/src/content/schema.ts, bdr/src/content/default.ts, bdr/src/proxy.ts |
10
- | [Cybersecurity Landing Page (/landing — the site's current main page)](features/security-landing-page.md) | A single-page **cybersecurity services marketing landing page** at **`/landing`** in the `bdr` repo — and, as of 2026-08-24, **the site's main page**: `/` **307 | bdr/src/app/landing/page.tsx, bdr/src/app/security.css, bdr/src/flow/screens/SecurityLanding.tsx, bdr/src/content/security.ts, bdr/src/components/LogoSymbol.tsx, bdr/src/components/AssistantMark.tsx, bdr/src/components/Ico.tsx, bdr/src/components/Particles.tsx, bdr/next.config.ts, bdr/eslint.config.mjs |
11
+ | [Cybersecurity Landing Page (/landing — the site's current main page)](features/security-landing-page.md) | A single-page **cybersecurity services marketing landing page** at **`/landing`** in the `bdr` repo — and, as of 2026-08-24, **the site's main page**: `/` **307 | bdr/src/app/landing/page.tsx, bdr/src/app/security.css, bdr/src/flow/screens/SecurityLanding.tsx, bdr/src/content/security.ts, bdr/src/components/LogoSymbol.tsx, bdr/src/components/AssistantMark.tsx, bdr/src/components/Ico.tsx, bdr/src/components/Particles.tsx, bdr/src/components/ChatPanel.tsx, bdr/src/components/ChatMarkdown.tsx, bdr/src/lib/talosChat.ts, bdr/next.config.ts, bdr/eslint.config.mjs |
11
12
  | [Vapi Integration — Assistants, Tools, Structured Output](features/vapi-integration.md) | Everything inside Vapi: the three assistants, the three shared tools, the shared structured-output schema, the Liquid-templated system prompt, and the Python sc | ai-bdr/vapi/templates/assistant.template.json, ai-bdr/vapi/templates/system-prompt.template.md, ai-bdr/prompts/archive/prompt-may-15.txt, ai-bdr/prompts/campaigns/healthcare-2026-03-18.md, ai-bdr/prompts/campaigns/healthcare-v2-2026-03-25.md, ai-bdr/prompts/templates/campaign-template.md, ai-bdr/scripts/update_assistant.py, ai-bdr/scripts/update_system_prompt.py, ai-bdr/scripts/update_structured_output.py, ai-bdr/scripts/update_call_summary_context.py, ai-bdr/scripts/fix_booking_guardrails.py, ai-bdr/scripts/get_assistant.py, ai-bdr/docs/vapi-firstmessage-timing-fix.md, ai-bdr/docs/vapi-voicemail-iphone-screening.md |
12
13
  | [Web Funnel — Built Next.js App (structure, stack, how to run)](features/web-funnel-app.md) | > **READ FIRST (2026-08-24) — the funnel is currently UNREACHABLE.** `/` now > **307-redirects to `/landing`**, the new cybersecurity landing page > ([security- | bdr/PLAN.md, bdr/next.config.ts, bdr/.gitignore, bdr/src/server/hubspot.ts, bdr/src/server/leadSink.ts, bdr/src/server/callbackService.ts, bdr/src/server/workerDialer.ts, bdr/src/server/mailer.ts, bdr/src/server/statusToken.ts, bdr/src/server/vapiCall.ts, bdr/src/server/callStatus.ts, bdr/src/lib/summaryText.ts, bdr/src/lib/emailFormat.ts, bdr/src/lib/callStatus.ts, bdr/src/app/api/share-summary/route.ts, bdr/src/app/api/call-status/route.ts, bdr/src/flow/shareSummaryApi.ts, bdr/src/flow/callStatusApi.ts, bdr/src/flow/useCallStatusViewModel.ts, bdr/src/flow/screens/Success.tsx, bdr/src/flow/screens/CallNow.tsx, bdr/src/flow/screens/Schedule.tsx, bdr/src/flow/screens/CallSummary.tsx, bdr/src/content/schema.ts, bdr/src/content/default.ts, bdr/test/togaEnrichment.test.ts, bdr/test/fastDial.test.ts, bdr/eslint.config.mjs, bdr/amplify.yml, bdr/src/app, bdr/src/app/layout.tsx, bdr/src/app/page.tsx, bdr/src/app/studio.css, bdr/src/lib/resolveCampaignId.ts, bdr/src/lib/scheduleSlots.ts, bdr/src/lib/formatPhone.ts, bdr/src/lib/analytics.ts, bdr/src/lib/rateLimit.ts, bdr/src/lib/clientIp.ts, bdr/src/proxy.ts, bdr/.env.example, bdr/src/components/GoogleAnalytics.tsx, bdr/src/components/RichText.tsx, bdr/src/content, bdr/src/components, bdr/src/flow, bdr/src/server, bdr/src/server/toga.ts, bdr/src/app/api, bdr/test, bdr/test/togaPrimaryPhone.test.ts, bdr/public, bdr/mockup/styles.css |
13
14
  | [Web Funnel — Next.js UI + Config-Driven Campaign Content](features/web-funnel-content-model.md) | > **Status note (RESOLVED 2026-07-16):** the content **contract** below (schema, > provider seam, adapters) is BUILT and QA'd (PLAN Phases 0–5). | bdr/src/content/schema.ts, bdr/src/content/provider.ts, bdr/src/content/useCampaign.ts, bdr/src/content/default.ts, bdr/src/lib/resolveCampaignId.ts, bdr/src/server/leadSink.ts, bdr/src/server/callbackService.ts, bdr/src/app/api/call-now/route.ts, bdr/src/app/api/call-later/route.ts, bdr/src/app/api/contact/route.ts |
@@ -6,11 +6,13 @@ project: AI-BDR
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-24
9
+ updated: 2026-08-25
10
10
  owners: [tcox]
11
11
  files:
12
12
  - ai-bdr-campaign-handoff.md
13
+ - bdr/src/lib/talosChat.ts
13
14
  related:
15
+ - landing-chat-drawer.md
14
16
  - security-landing-page.md
15
17
  - web-funnel-app.md
16
18
  - ../architecture.md
@@ -34,11 +36,20 @@ architecture deep-dive in `docs/ai-bdr-campaign-chat-architecture.md`). This
34
36
  knowledge doc distills the contract and records the load-bearing decisions and
35
37
  gotchas — the source handoff carries the full copy-paste implementation code.
36
38
 
37
- **Direct relevance to BDR:** the cybersecurity landing page's inert
38
- **"Ask Me Anything"** header CTA (see [security-landing-page.md](security-landing-page.md)
39
- the mockup's un-ported chat drawer) is exactly the kind of consumer this widget
40
- was specified for, and the first live campaign is **"External Pen Testing"** —
41
- the same offer the landing page sells.
39
+ **The first consumer now exists.** As of 2026-08-24 the `bdr` cybersecurity landing page
40
+ ships a chat drawer against this contract, grounded in the "External Pen Testing"
41
+ campaign the same offer the landing sells. It lives in `bdr/src/lib/talosChat.ts`
42
+ (adapter) + `ChatPanel.tsx` / `ChatMarkdown.tsx`, and is documented in
43
+ [landing-chat-drawer.md](landing-chat-drawer.md). Read that doc before building the
44
+ **second** consumer; it is the worked example of this contract.
45
+
46
+ **It was NOT built on assistant-ui.** The *Frontend build* section below still describes
47
+ the handoff's original `@assistant-ui/react` + `useLocalRuntime` recipe, which remains a
48
+ valid path. BDR deliberately went a different way: a hand-rolled drawer plus a
49
+ **blox-shaped adapter** (`onSend(text) => Promise<TalosResponse>`, matching
50
+ `@agilant/toga-blox`'s `TalosAdapter` seam), so the shell can later be swapped for blox's
51
+ shared `TalosPanel` without rewriting the backend layer. Treat assistant-ui as one
52
+ option, not the house standard.
42
53
 
43
54
  ## Design decision (settled — do not re-litigate)
44
55
 
@@ -158,6 +169,14 @@ from `data`.
158
169
 
159
170
  ## Gotchas
160
171
 
172
+ - **Every consumer domain must be allowlisted by the Talos backend owner** — the
173
+ origin/UA gate on `talos-session` / `talos-chat` / `campaign` is per-origin, so
174
+ `localhost:3000`, each sandbox host (e.g. `bdr.dev.sandbox.togatech.com`), and the
175
+ production domain each need adding **before** the widget can answer live. Budget this
176
+ as a real dependency on someone else, not a config flag you own. A well-built consumer
177
+ degrades silently here (BDR's does), which makes "it works on my machine"
178
+ indistinguishable from "the backend refused us" unless you check for a live-only
179
+ signal such as backend-chosen `suggestions`.
161
180
  - **Presigned deck-image URLs EXPIRE (~7 days).** `image_url` is a presigned S3
162
181
  URL because `CAMPAIGN_ASSET_CDN_BASE_URL` is currently unset — do not cache
163
182
  long-term; re-fetch the campaign read on page load / image error. Once the
@@ -181,6 +200,13 @@ from `data`.
181
200
  internal-only** now that campaign traffic rides the same path.
182
201
 
183
202
  ## Change history
203
+ - 2026-08-24 — First consumer built and shipped into the `bdr` working tree: the
204
+ `/landing` chat drawer ([landing-chat-drawer.md](landing-chat-drawer.md)), grounded in
205
+ the "External Pen Testing" campaign. Recorded that it deliberately did **not** use the
206
+ handoff's assistant-ui recipe, using a blox-`TalosAdapter`-shaped seam instead so the
207
+ shell can be swapped for blox's shared `TalosPanel` later. Added the per-origin
208
+ allowlist gotcha — every consumer domain needs the Talos backend owner to allowlist it,
209
+ and a graceful consumer hides that failure. (tcox)
184
210
  - 2026-08-24 — Initial doc: captured the consolidated AI-BDR campaign chat
185
211
  handoff (backend contract at api.togaiq.com + frontend widget spec on
186
212
  assistant-ui). Markdown + structured-data format settled over XML tags;
@@ -0,0 +1,176 @@
1
+ ---
2
+ title: Talos Chat Drawer on /landing (first campaign-chat consumer)
3
+ framework: "2.0"
4
+ repo: ai-bdr
5
+ project: AI-BDR
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-08-25
10
+ owners: [tcox]
11
+ files:
12
+ - bdr/src/components/ChatPanel.tsx
13
+ - bdr/src/components/ChatMarkdown.tsx
14
+ - bdr/src/lib/talosChat.ts
15
+ - bdr/src/content/security.ts
16
+ - bdr/src/flow/screens/SecurityLanding.tsx
17
+ - bdr/src/app/security.css
18
+ - bdr/test/talosChat.test.ts
19
+ - bdr/test/chatMarkdown.test.ts
20
+ related:
21
+ - security-landing-page.md
22
+ - campaign-chat-handoff.md
23
+ - web-funnel-app.md
24
+ - ../../toga-blox/features/talos-assistant.md
25
+ ---
26
+
27
+ ## What this is
28
+
29
+ The **right-anchored chat drawer on `/landing`**, wired to the **real** Talos
30
+ campaign-chat backend at `https://api.togaiq.com`. It is the **first live consumer**
31
+ of the contract in [campaign-chat-handoff.md](campaign-chat-handoff.md), grounded in
32
+ campaign `43fdf2b6-7a5d-4e85-be6b-911f42aa787f` ("External Pen Testing") — the same
33
+ offer the landing page sells.
34
+
35
+ It opens from **both** entry points that were previously inert: the header CTA
36
+ ("Ask Alex Anything") and the hero "Learn more" button.
37
+
38
+ Three pieces, deliberately separated:
39
+
40
+ | File | Role | Disposable? |
41
+ |---|---|---|
42
+ | `components/ChatPanel.tsx` | Drawer **shell** (scrim, header, message list, chips, composer) | **Yes** — planned replacement by blox `TalosPanel` |
43
+ | `lib/talosChat.ts` | Backend **adapter** (session, message shaping, fallback) | No — the durable piece |
44
+ | `components/ChatMarkdown.tsx` | Safe markdown **renderer** for the reply | No — portable as-is |
45
+
46
+ ## How it works
47
+
48
+ 1. **Fingerprint.** `getFingerprint()` returns a per-browser 64-lowercase-hex id
49
+ persisted in `localStorage` under `talos_fp` (32 random bytes), with an in-memory
50
+ fallback when storage is unavailable.
51
+ 2. **Session token.** `POST /api/ai/talos-session` mints a ~15-min JWT bound to that
52
+ fingerprint. It is cached in the adapter and re-minted **exactly once** on a 401;
53
+ a second 401 falls through to the scripted fallback rather than looping.
54
+ 3. **Turn.** Non-streaming `POST /api/ai/talos-chat` with `Bearer <token>`,
55
+ `campaign_id`, and the shaped `messages` array.
56
+ 4. **Render.** `message` goes through `ChatMarkdown`; `suggestions` become quick-reply
57
+ chips whose text is sent as the next user message.
58
+
59
+ **Message-shape enforcement lives in `buildApiMessages()`**, not in the UI. The backend
60
+ requires alternating `user`/`assistant`, starting **and** ending with `user`, max 30 —
61
+ so the builder drops the canned greeting, merges consecutive same-role turns, and
62
+ trims from the front to the cap while preserving alternation. The visible transcript
63
+ and the wire transcript are deliberately not the same list.
64
+
65
+ **Adapter seam:** `createTalosChatAdapter(options)` returns a `TalosAdapter` whose only
66
+ method is `onSend(text) => Promise<TalosResponse>` — intentionally the same shape as
67
+ blox's `TalosAdapter` (see *Bridge to blox* below).
68
+
69
+ Base URL resolution: `options.baseUrl ?? process.env.NEXT_PUBLIC_TALOS_API_BASE ??
70
+ "https://api.togaiq.com"`.
71
+
72
+ ## Offline fallback (the drawer never dead-ends)
73
+
74
+ When the backend is unreachable — offline, **origin not allowlisted**, 5xx, timeout —
75
+ the adapter answers from the mockup's scripted `askAlex` answers, which now live as
76
+ **data** in `src/content/security.ts` under the `talos.fallback` group (not hardcoded
77
+ in the adapter).
78
+
79
+ - Fallback replies are flagged `offline: true` and carry **no** suggestion chips.
80
+ - **That is how you tell live from fallback in the UI:** live replies carry
81
+ backend-chosen chips; fallback replies have none.
82
+ - Alternation is preserved across a fallback turn, so a later live turn is still a
83
+ valid request (covered by a test).
84
+
85
+ ## Safety
86
+
87
+ - `ChatMarkdown` supports only paragraphs, `- ` bullets, and `**bold**`. It emits
88
+ **only** text nodes plus `p` / `ul` / `li` / `strong`. **No HTML parsing, no links,
89
+ no `dangerouslySetInnerHTML`** — html-looking content stays literal text (tested).
90
+ An unclosed `**` stays literal.
91
+ - Only rendered fields (`message`, `suggestions`, `cta`, `cited_slides`) are mapped
92
+ into the response type by `toTalosResponse()`. The backend's **silent
93
+ lead/qualification fields are never read** — deliberate, per the handoff.
94
+
95
+ ## Deliberate deviations from the mockup drawer
96
+
97
+ - **"Call me now" is NOT rendered.** Its destination is the parked studio call screen,
98
+ unreachable from this page. The standing drawer action is **"Book a meeting"** →
99
+ the same Calendly href as the page's primary CTA.
100
+ - **`cta` and `cited_slides` are captured and typed but not rendered yet.** Both are
101
+ clean follow-ups; `cited_slides` additionally needs `GET /api/ai/campaign/{id}` plus
102
+ presigned-URL freshness handling (those URLs expire ~7 days — see the handoff).
103
+
104
+ ## Bridge to blox (TRUE-80692 — "bridge now, blox later")
105
+
106
+ blox ships a shared Talos component
107
+ ([talos-assistant.md](../../toga-blox/features/talos-assistant.md), apeterson,
108
+ 2026-08-20). BDR does **not** use it yet, for two blox-side reasons, both unscheduled:
109
+
110
+ - blox is **not published to npm** for this component (toga25-supply consumes it via a
111
+ local symlink; BDR cannot symlink a Next app dependency the same way), and
112
+ - blox **peers cap React at ^18**, while BDR is on **React 19.2.4**.
113
+
114
+ So the decision: build the shell now, swap it later.
115
+
116
+ - `ChatPanel.tsx` is **deliberately disposable** — expect it to be deleted and replaced
117
+ by blox `TalosPanel`.
118
+ - `talosChat.ts` **deliberately mirrors blox's `TalosAdapter` seam**
119
+ (`onSend(text) => Promise<TalosResponse>`), so the swap is a **re-wire, not a rebuild**.
120
+ - `talosChat.ts` is the candidate implementation for blox's deferred *"real `onSend`
121
+ backend adapter"* ticket — contribute it upstream when that ticket is picked up
122
+ (mention to apeterson). The one env-ism to fix on the way: the
123
+ `process.env.NEXT_PUBLIC_TALOS_API_BASE` default is Next-specific; blox consumers are
124
+ Vite, so it becomes a **required `baseUrl` option**.
125
+ - `ChatMarkdown.tsx` is portable as-is; it would need `className` → `--talos-*`
126
+ tokenization.
127
+ - **Design caveat:** blox `TalosPanel`'s spacing/density is not yet tokenized (its
128
+ documented theming ceiling), so even fully themed it will **not** match the security
129
+ mockup drawer pixel-for-pixel. Accept that at swap time or fund the spacing-token pass.
130
+
131
+ ## Styling
132
+
133
+ The `.chatveil` / `.chatpanel` block is ported from the mockup's `styles.css`
134
+ (1177–1220) into `security.css` and is **scoped under `.security-shell`** like every
135
+ other landing rule. `z-index: 120`, width `min(400px, 92vw)`, reduced-motion respected.
136
+ `.chatmd-p` / `.chatmd-list` carry the reply rhythm. Escape and scrim click close the
137
+ drawer; focus moves into the composer on open and is restored to the opener on close.
138
+
139
+ ## Gotchas
140
+
141
+ - **`api.togaiq.com` chat endpoints are origin/UA-gated.** `localhost:3000`,
142
+ `bdr.dev.sandbox.togatech.com`, and the eventual production domain **must be
143
+ allowlisted by the Talos backend owner**. Until they are, the drawer silently answers
144
+ from the scripted fallback and looks like it works. Check for suggestion chips before
145
+ concluding the backend is live.
146
+ - **Do not "fix" the transcript by sending the visible message list.** The greeting and
147
+ any merged/trimmed turns would break the strict alternating shape and return a 422.
148
+ - **The chat is fully client-side**, which is why `/landing` still builds as a
149
+ **prerendered static** route. Adding a server call here changes that.
150
+ - **`/landing` is not rate-limited** (`src/proxy.ts` matches only `/` and the five API
151
+ routes). The drawer talks to a third-party origin, not a BDR API route, so the
152
+ limiter still does not apply — but the abuse surface now exists on the page.
153
+
154
+ ## How to work on it
155
+
156
+ - 30 new Vitest tests across `test/talosChat.test.ts` and `test/chatMarkdown.test.ts`
157
+ (message-shape rules including the 30-cap alternation, 401 re-mint-once, fallback on
158
+ network error and on 5xx, alternation preserved across a fallback turn, adapter
159
+ reset, markdown safety). Suite **367/367 green**; `tsc`, `eslint` (incl. the
160
+ no-em-dash rule), and `next build` all clean as of 2026-08-24.
161
+ - **Nothing is committed** — the drawer lives in the `bdr` working tree only, awaiting
162
+ the developer's branch/commit go-ahead.
163
+
164
+ ## Change history
165
+ - 2026-08-24 — Initial doc. BUILT the `/landing` Talos chat drawer wired to the real
166
+ campaign-chat backend: `ChatPanel.tsx` (right-anchored drawer ported from the security
167
+ mockup), `lib/talosChat.ts` (fingerprint + 15-min session token + message-shape
168
+ enforcement + scripted offline fallback), `ChatMarkdown.tsx` (link-free, HTML-free
169
+ markdown subset), the `.chatveil`/`.chatpanel` CSS block, and the `talos` content group.
170
+ Both previously-inert entry points (header CTA "Ask Alex Anything", hero "Learn more")
171
+ now open it. DECIDED "bridge now, blox later" for TRUE-80692 — blox is unpublished and
172
+ React-18-capped, so the shell is disposable while the adapter mirrors blox's
173
+ `TalosAdapter` seam for a later re-wire. DECIDED not to render the mockup's "Call me
174
+ now" (parked studio destination) and to defer `cta`/`cited_slides` rendering. Recorded
175
+ the origin/UA allowlist dependency as the reason the drawer may silently answer from
176
+ fallback. 30 new tests, 367/367 green. Uncommitted at capture. (tcox)
@@ -6,7 +6,7 @@ project: AI-BDR
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-24
9
+ updated: 2026-08-25
10
10
  owners: [tcox]
11
11
  files:
12
12
  - bdr/src/app/landing/page.tsx
@@ -17,9 +17,14 @@ files:
17
17
  - bdr/src/components/AssistantMark.tsx
18
18
  - bdr/src/components/Ico.tsx
19
19
  - bdr/src/components/Particles.tsx
20
+ - bdr/src/components/ChatPanel.tsx
21
+ - bdr/src/components/ChatMarkdown.tsx
22
+ - bdr/src/lib/talosChat.ts
20
23
  - bdr/next.config.ts
21
24
  - bdr/eslint.config.mjs
22
25
  related:
26
+ - landing-chat-drawer.md
27
+ - campaign-chat-handoff.md
23
28
  - web-funnel-app.md
24
29
  - web-funnel-content-model.md
25
30
  - ../architecture.md
@@ -39,8 +44,11 @@ mockup: `BDR/AI BDR - Security/` (a React 18 UMD + in-browser Babel prototype
39
44
  **`Capabilities` screen**; because `src/flow/screens/Capabilities.tsx` already exists as a
40
45
  studio screen, it was ported under the name **`SecurityLanding`**.
41
46
 
42
- **Status: UI only.** Nothing is wired to a backend no lead capture, no Toga/HubSpot
43
- call, no analytics events of its own. Wiring is a later decision (see *CTA wiring* below).
47
+ **Status (updated 2026-08-24): one live backend, nothing else.** The page now carries a
48
+ **Talos chat drawer wired to the real campaign-chat backend** see
49
+ [landing-chat-drawer.md](landing-chat-drawer.md), which owns that subject. Everything
50
+ else is still UI only: no form, no lead capture, no Toga/HubSpot call, no analytics
51
+ events of its own.
44
52
 
45
53
  ## Page structure
46
54
 
@@ -129,8 +137,25 @@ does not define or defines differently.
129
137
  **CAVEAT: that URL is a placeholder carried over from the mockup** (the mockup's own
130
138
  comment says "replace with the real TOGA Calendly link") and the slug's liveness has
131
139
  **not** been verified. Confirm it before pointing traffic at the page.
132
- - **"Learn more"** and the header CTA **"Ask Me Anything"** render **inert**. In the
133
- mockup, "Ask Me Anything" opened a chat drawer; **the drawer was not ported.**
140
+ - **"Learn more"** and the header CTA (**"Ask Alex Anything"** renamed 2026-08-24 from
141
+ the mockup's "Ask Me Anything") both **open the Talos chat drawer** as of 2026-08-24.
142
+ Neither is inert any more. The drawer, its backend adapter, and its offline fallback
143
+ are documented in [landing-chat-drawer.md](landing-chat-drawer.md).
144
+
145
+ ## Responsive / mobile pass (original work, not ported)
146
+
147
+ The mockup ships **no** landing-specific mobile CSS below its 900px hero-stack and 760px
148
+ stats/matters breakpoints, so the phone treatment below ~760px was **designed here**, not
149
+ ported. All of it is scoped under `.security-shell`.
150
+
151
+ - **`@media (max-width: 560px)`** — hero title re-clamped to `clamp(29px, 8.4vw, 35px)`;
152
+ the two hero CTAs stack **full-width** at `height: 54px`; value-tile padding `20px`;
153
+ matters-card / stat padding trimmed; stat figure `23px`; section spacing tightened.
154
+ **`.lp-value-motes` inset pulled in from `-42px/-34px` to `-30px/-10px`** — at
155
+ full-width the mote spill poked past the viewport edge and opened **horizontal
156
+ scroll** on phones. Do not widen it back without re-checking on a real device.
157
+ - **`@media (max-width: 420px)`** — **`.wordmark-tech` is hidden** (the letterspaced
158
+ "TECHNOLOGY" suffix and the header pill cannot share a ~360px topbar); stats gap `12px`.
134
159
 
135
160
  ## How to work on it
136
161
 
@@ -142,13 +167,15 @@ does not define or defines differently.
142
167
 
143
168
  ## Known gaps / pending work
144
169
 
145
- - **Mobile pass is pending.** The mockup has almost no landing-specific mobile CSS: only a
146
- 900px hero-stack and a 760px stats/matters breakpoint. Its big "mobile pass" block
147
- contains **zero `.lp-*` rules**, so there is no design to port the responsive
148
- treatment below ~760px is an open design question, not a porting oversight.
149
- - **Chat drawer not ported** (the header CTA's mockup behavior).
150
- - **Calendly URL unverified** (above).
170
+ - **Calendly URL unverified** (above) still the top open item, and now also the
171
+ drawer's "Book a meeting" destination, so a bad slug breaks two paths.
172
+ - **Chat drawer's origin allowlist is not done** `api.togaiq.com` is origin/UA gated,
173
+ so until localhost / sandbox / prod domains are allowlisted the drawer silently answers
174
+ from its scripted fallback (see [landing-chat-drawer.md](landing-chat-drawer.md)).
151
175
  - No form, no lead capture, no landing-specific analytics.
176
+ - ~~Mobile pass pending~~ — **done 2026-08-24** (see *Responsive / mobile pass* above).
177
+ - ~~Chat drawer not ported~~ — **done 2026-08-24**, and wired to the real backend rather
178
+ than re-creating the mockup's scripted-only behavior.
152
179
 
153
180
  ## Gotchas
154
181
 
@@ -182,6 +209,14 @@ does not define or defines differently.
182
209
  the page gains a form or reads a query param.
183
210
 
184
211
  ## Change history
212
+ - 2026-08-24 — Closed both of the doc's open gaps. BUILT the **mobile pass** as original
213
+ work (560px and 420px breakpoints under `.security-shell`; the `.lp-value-motes` inset
214
+ was pulled in to kill horizontal scroll, and `.wordmark-tech` is hidden under 420px) —
215
+ the mockup had no landing-specific mobile CSS to port. BUILT the **Talos chat drawer**,
216
+ wired to the real campaign-chat backend, opened by both previously-inert entry points
217
+ (header CTA, now "Ask Alex Anything", and hero "Learn more"); the drawer is its own
218
+ subject in [landing-chat-drawer.md](landing-chat-drawer.md). Page remains prerendered
219
+ static (chat is fully client-side); still no form, lead capture, or analytics. (tcox)
185
220
  - 2026-08-24 — Initial doc. BUILT the cybersecurity landing page at `/landing`, ported
186
221
  pixel-faithfully from the new `BDR/AI BDR - Security/` mockup (its `Capabilities` screen,
187
222
  renamed `SecurityLanding` to avoid the studio-screen collision) and made it the site's
@@ -198,5 +233,3 @@ does not define or defines differently.
198
233
  (chat drawer not ported), and that the mobile pass is pending because the mockup has no
199
234
  landing-specific mobile CSS. tsc + lint + build clean, `/landing` prerendered static,
200
235
  `GET /` → 307 verified. All work uncommitted in the working tree at capture. (tcox)
201
- </content>
202
- </invoke>
@@ -6,8 +6,8 @@ project: TOGa Blox
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-20
10
- owners: [apeterson]
9
+ updated: 2026-08-25
10
+ owners: [apeterson, tcox]
11
11
  files:
12
12
  - toga-blox/src/components/Talos/TalosLauncher.tsx
13
13
  - toga-blox/src/components/Talos/TalosPanel.tsx
@@ -23,6 +23,7 @@ related:
23
23
  - ../architecture.md
24
24
  - ../workflows/dynamic-publish-pipeline.md
25
25
  - ../../toga25-supply/features/talos-integration.md
26
+ - ../../ai-bdr/features/landing-chat-drawer.md
26
27
  ---
27
28
 
28
29
  ## Summary
@@ -77,10 +78,25 @@ Open questions were handed to the UX/UI team.
77
78
  ## Gotchas
78
79
 
79
80
  - The real chat backend is a later ticket — `onSend` is stubbed; do not assume live responses.
81
+ **A working candidate implementation already exists outside blox:** `bdr/src/lib/talosChat.ts`
82
+ was written against the same `onSend(text) => Promise<TalosResponse>` seam and talks to the
83
+ live Talos campaign-chat backend (session token, fingerprint, strict message shaping, offline
84
+ fallback) — see
85
+ [AI-BDR landing chat drawer](../../ai-bdr/features/landing-chat-drawer.md). Consider
86
+ upstreaming it when the adapter ticket is picked up; the only env-ism to change is its
87
+ Next-specific `process.env.NEXT_PUBLIC_TALOS_API_BASE` default, which becomes a required
88
+ `baseUrl` option for Vite consumers.
89
+ - **BDR cannot consume blox Talos today** — blox is unpublished for this component and its peers
90
+ cap React at `^18`, while `bdr` is on React 19.2.4. That is why BDR hand-rolled a disposable
91
+ panel shell instead of waiting; both blockers are blox-side and unscheduled.
80
92
  - blox `dist` is gitignored (shipped via publish, not the branch). Other consumers only get
81
93
  Talos after blox is **published** per the `_sandbox-dev` dist-tag workflow — see
82
94
  [Dynamic npm Publish Pipeline](../workflows/dynamic-publish-pipeline.md). toga25-supply
83
95
  currently consumes it via a local symlink.
84
96
 
85
97
  ## Change history
98
+ - 2026-08-24 — Cross-reference only (no blox code change): recorded that `bdr` built a live
99
+ backend adapter against this component's `onSend` seam (`bdr/src/lib/talosChat.ts`) as a
100
+ candidate for the deferred real-backend ticket, and that BDR cannot consume blox Talos yet
101
+ (unpublished + React `^18` peer cap vs BDR's React 19). (tcox)
86
102
  - 2026-08-20 — Built Talos shared AI-assistant component (launcher + docked/expanded chat panel): pure-UI + injected `TalosAdapter`, controlled open/expanded/width, fully `--talos-*` tokenized styling with typed `TalosTheme` overrides, stub adapter. Two adversarial review passes hardened it (removed a `window.dispatchEvent("resize")` side channel and a hardcoded initials literal; moved resize into an effect with cleanup + rAF throttle + keyboard `role="separator"`; SSR-safe portal guard; memoized message/handlers; restored the attach button + 11px card radius). Documented the spacing/density theming ceiling as future work (apeterson).
@@ -28,7 +28,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
28
28
  - **toga2-hub** (TOGa Hub) — 2 doc(s) → [2.0/apps/toga2-hub/INDEX.md](2.0/apps/toga2-hub/INDEX.md)
29
29
  - **talos** (TOGa IQ) — 7 doc(s) → [2.0/apps/talos/INDEX.md](2.0/apps/talos/INDEX.md)
30
30
  - **voice-to-voice** (TOGa Voice) — 4 doc(s) → [2.0/apps/voice-to-voice/INDEX.md](2.0/apps/voice-to-voice/INDEX.md)
31
- - **ai-bdr** (AI-BDR) — 11 doc(s) → [2.0/apps/ai-bdr/INDEX.md](2.0/apps/ai-bdr/INDEX.md)
31
+ - **ai-bdr** (AI-BDR) — 12 doc(s) → [2.0/apps/ai-bdr/INDEX.md](2.0/apps/ai-bdr/INDEX.md)
32
32
  - **toga2-commerce** (TOGa Commerce) — 19 doc(s) → [2.0/apps/toga2-commerce/INDEX.md](2.0/apps/toga2-commerce/INDEX.md)
33
33
  - **toga25-supply** (TOGa 2.5 Supply) — 12 doc(s) → [2.0/apps/toga25-supply/INDEX.md](2.0/apps/toga25-supply/INDEX.md)
34
34
  - **toga-blox** (TOGa Blox) — 10 doc(s) → [2.0/apps/toga-blox/INDEX.md](2.0/apps/toga-blox/INDEX.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.640",
3
+ "version": "1.0.641",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",