Skip to content

Commit 8e9441b

Browse files
bloveclaude
andcommitted
feat(website): wire the docs -> cockpit handoff for deep-agents and runtimes
The cockpit -> docs direction shipped with both libraries (COCKPIT_DOCS_LINKS covers all six deep-agents entries and all four runtimes entries), but the reverse table only knew the five first-iteration pages. Every deep-agents page (#937) and every runtimes page (#913) sent its Run/Code/API buttons to Cockpit home instead of the demo the page describes. Add the 16 missing entries: - deep-agents: the five capability pages map to their core-capabilities topic; the introduction maps to deep-agents/getting-started/overview. - runtimes: all three pages of each runtime section (overview, quickstart, how-it-connects) map to that runtime's one demo, since a single demo serves them equally well; the introduction maps to runtimes/getting-started/overview. Also add deep-agents and runtimes to AnalyticsLibrary. Without it every handoff from these two libraries would have been attributed to 'unknown', so the new links would be invisible in the funnel they exist to feed. Each of the ten destination URLs was checked against production and returns a hard 200. The check discriminates: an unknown topic 307s to the fallback and an unknown product 500s, so the 200s are real pages rather than SPA soft-200s. Tests: the exact pin is updated, plus four guards — every key names a page that exists in docs-config (a typo'd key is otherwise invisible: the page just keeps the Cockpit-home fallback), the deep-agents/runtimes links round-trip against COCKPIT_DOCS_LINKS, the analytics library is no longer 'unknown', and each runtime section's three pages resolve to the same demo. All four were mutation-tested to confirm they fail when the mapping is wrong. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 2ed9d11 commit 8e9441b

3 files changed

Lines changed: 283 additions & 2 deletions

File tree

apps/website/src/lib/analytics/events.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,14 @@ export type CtaId =
9090
// MediumSwitcher derives ids from section id + medium key at runtime
9191
| `medium_${string}`;
9292

93-
export type AnalyticsLibrary = 'langgraph' | 'render' | 'chat' | 'ag-ui' | 'unknown';
93+
export type AnalyticsLibrary =
94+
| 'langgraph'
95+
| 'render'
96+
| 'chat'
97+
| 'ag-ui'
98+
| 'deep-agents'
99+
| 'runtimes'
100+
| 'unknown';
94101

95102
export type WhitepaperId = 'overview' | 'angular' | 'render' | 'chat';
96103

apps/website/src/lib/cockpit-links.spec.ts

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { cockpitManifest } from '@threadplane/cockpit-registry';
1+
import { COCKPIT_DOCS_LINKS, cockpitManifest } from '@threadplane/cockpit-registry';
22
import { describe, expect, it } from 'vitest';
3+
import { findDocsPage } from './docs-config';
34
import {
45
buildCockpitHandoffProperties,
56
buildCockpitModeHref,
@@ -10,6 +11,54 @@ import {
1011
describe('Docs-to-Cockpit links', () => {
1112
it('contains the exhaustive first-iteration mapping set', () => {
1213
expect(docsCockpitMappings).toEqual({
14+
'deep-agents/getting-started/introduction': {
15+
product: 'deep-agents', section: 'getting-started', topic: 'overview', page: 'overview', language: 'python',
16+
},
17+
'deep-agents/capabilities/planning': {
18+
product: 'deep-agents', section: 'core-capabilities', topic: 'planning', page: 'overview', language: 'python',
19+
},
20+
'deep-agents/capabilities/filesystem': {
21+
product: 'deep-agents', section: 'core-capabilities', topic: 'filesystem', page: 'overview', language: 'python',
22+
},
23+
'deep-agents/capabilities/subagents': {
24+
product: 'deep-agents', section: 'core-capabilities', topic: 'subagents', page: 'overview', language: 'python',
25+
},
26+
'deep-agents/capabilities/memory': {
27+
product: 'deep-agents', section: 'core-capabilities', topic: 'memory', page: 'overview', language: 'python',
28+
},
29+
'deep-agents/capabilities/skills': {
30+
product: 'deep-agents', section: 'core-capabilities', topic: 'skills', page: 'overview', language: 'python',
31+
},
32+
'runtimes/getting-started/introduction': {
33+
product: 'runtimes', section: 'getting-started', topic: 'overview', page: 'overview', language: 'python',
34+
},
35+
'runtimes/aws-strands/overview': {
36+
product: 'runtimes', section: 'core-capabilities', topic: 'aws-strands', page: 'overview', language: 'python',
37+
},
38+
'runtimes/aws-strands/quickstart': {
39+
product: 'runtimes', section: 'core-capabilities', topic: 'aws-strands', page: 'overview', language: 'python',
40+
},
41+
'runtimes/aws-strands/how-it-connects': {
42+
product: 'runtimes', section: 'core-capabilities', topic: 'aws-strands', page: 'overview', language: 'python',
43+
},
44+
'runtimes/microsoft-agent-framework/overview': {
45+
product: 'runtimes', section: 'core-capabilities', topic: 'microsoft-agent-framework', page: 'overview', language: 'python',
46+
},
47+
'runtimes/microsoft-agent-framework/quickstart': {
48+
product: 'runtimes', section: 'core-capabilities', topic: 'microsoft-agent-framework', page: 'overview', language: 'python',
49+
},
50+
'runtimes/microsoft-agent-framework/how-it-connects': {
51+
product: 'runtimes', section: 'core-capabilities', topic: 'microsoft-agent-framework', page: 'overview', language: 'python',
52+
},
53+
'runtimes/mastra/overview': {
54+
product: 'runtimes', section: 'core-capabilities', topic: 'mastra', page: 'overview', language: 'python',
55+
},
56+
'runtimes/mastra/quickstart': {
57+
product: 'runtimes', section: 'core-capabilities', topic: 'mastra', page: 'overview', language: 'python',
58+
},
59+
'runtimes/mastra/how-it-connects': {
60+
product: 'runtimes', section: 'core-capabilities', topic: 'mastra', page: 'overview', language: 'python',
61+
},
1362
'langgraph/guides/streaming': {
1463
product: 'langgraph', section: 'core-capabilities', topic: 'streaming', page: 'overview', language: 'python',
1564
},
@@ -124,4 +173,85 @@ describe('Docs-to-Cockpit links', () => {
124173
)).toBe(true);
125174
}
126175
});
176+
177+
// A typo'd key is invisible at runtime: the page just never resolves and the
178+
// reader silently keeps the Cockpit-home fallback. Pin the keys to the real
179+
// content tree so a typo (or a docs rename) fails here instead.
180+
it('keys every mapping to a docs page that exists', () => {
181+
for (const key of Object.keys(docsCockpitMappings)) {
182+
const [library, section, slug] = key.split('/');
183+
expect(findDocsPage(library, section, slug), key).toBeDefined();
184+
}
185+
});
186+
187+
// The two directions are separate tables in separate packages. Where the
188+
// Cockpit side already points at a docs page, that page must point back at
189+
// the same capability, or the round trip lands somewhere else.
190+
it('round-trips the deep-agents and runtimes links back to their capability', () => {
191+
const forward = Object.entries(COCKPIT_DOCS_LINKS).filter(([key]) =>
192+
key.startsWith('deep-agents/') || key.startsWith('runtimes/'),
193+
);
194+
expect(forward).toHaveLength(10);
195+
196+
for (const [key, docsPath] of forward) {
197+
const [product, section, topic] = key.split('/');
198+
const [library, docsSection, slug] = docsPath.replace('/docs/', '').split('/');
199+
200+
expect(resolveCockpitIdentity(library, docsSection, slug), key).toEqual(
201+
expect.objectContaining({ product, section, topic }),
202+
);
203+
}
204+
});
205+
206+
it('reports deep-agents and runtimes as themselves, not unknown', () => {
207+
expect(
208+
buildCockpitHandoffProperties(
209+
{ library: 'deep-agents', section: 'capabilities', slug: 'planning' },
210+
'Run',
211+
),
212+
).toEqual({
213+
library: 'deep-agents',
214+
source_section: 'capabilities',
215+
source_slug: 'planning',
216+
destination_product: 'deep-agents',
217+
destination_capability: 'planning',
218+
requested_mode: 'run',
219+
mapped: true,
220+
});
221+
222+
expect(
223+
buildCockpitHandoffProperties(
224+
{ library: 'runtimes', section: 'mastra', slug: 'quickstart' },
225+
'Code',
226+
).library,
227+
).toBe('runtimes');
228+
});
229+
230+
// Every page of a runtime's docs section shares that runtime's one demo, so
231+
// a reader on the quickstart gets the same handoff as one on the overview.
232+
it('sends every page of a runtime section to that runtime demo', () => {
233+
for (const slug of ['overview', 'quickstart', 'how-it-connects']) {
234+
expect(
235+
buildCockpitModeHref(
236+
{ library: 'runtimes', section: 'aws-strands', slug },
237+
'Run',
238+
'https://cockpit.example',
239+
),
240+
).toBe(
241+
'https://cockpit.example/runtimes/core-capabilities/aws-strands/overview/python?mode=run',
242+
);
243+
}
244+
});
245+
246+
it('sends a deep-agents capability page to its capability demo', () => {
247+
expect(
248+
buildCockpitModeHref(
249+
{ library: 'deep-agents', section: 'capabilities', slug: 'skills' },
250+
'Code',
251+
'https://cockpit.example',
252+
),
253+
).toBe(
254+
'https://cockpit.example/deep-agents/core-capabilities/skills/overview/python?mode=code',
255+
);
256+
});
127257
});

apps/website/src/lib/cockpit-links.ts

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,149 @@ export interface DocsIdentity {
1111
export const COCKPIT_ENVIRONMENT_LABEL =
1212
process.env.NEXT_PUBLIC_COCKPIT_ENVIRONMENT_LABEL ?? 'Shared development';
1313

14+
/**
15+
* Documentation page -> Cockpit capability (the reverse of
16+
* `COCKPIT_DOCS_LINKS` in `@threadplane/cockpit-registry`).
17+
*
18+
* Keyed by `${library}/${section}/${slug}` — the three segments of the docs
19+
* route, `/docs/<library>/<section>/<slug>`. Values are a full Cockpit
20+
* identity, because the Cockpit route carries five segments; the extra two are
21+
* fixed (`page: 'overview'`, `language: 'python'`) for every manifest entry
22+
* today, so they are written out rather than derived.
23+
*
24+
* Rules for this table:
25+
*
26+
* - An unmapped page is not an error. `resolveCockpitIdentity` returns null and
27+
* the control plane sends the reader to Cockpit home instead of guessing a
28+
* URL — the five-segment formula 404s for pages that have no demo.
29+
* - Several docs pages may share one Cockpit target. The runtimes library
30+
* documents each runtime across three pages (overview, quickstart,
31+
* how-it-connects) that one demo serves equally well.
32+
* - An `introduction` maps to its product's `getting-started/overview` entry.
33+
* Those entries are `entryKind: 'docs-only'` in the manifest, so Run mode
34+
* lands on the product's Cockpit overview rather than a live demo — still a
35+
* better destination than Cockpit home, and it keeps the Capability row
36+
* truthful.
37+
* - The spec pins this object exactly and cross-checks every target against
38+
* `cockpitManifest`, so a Cockpit topic rename breaks the test rather than
39+
* the link.
40+
*/
1441
export const docsCockpitMappings = {
42+
'deep-agents/getting-started/introduction': {
43+
product: 'deep-agents',
44+
section: 'getting-started',
45+
topic: 'overview',
46+
page: 'overview',
47+
language: 'python',
48+
},
49+
'deep-agents/capabilities/planning': {
50+
product: 'deep-agents',
51+
section: 'core-capabilities',
52+
topic: 'planning',
53+
page: 'overview',
54+
language: 'python',
55+
},
56+
'deep-agents/capabilities/filesystem': {
57+
product: 'deep-agents',
58+
section: 'core-capabilities',
59+
topic: 'filesystem',
60+
page: 'overview',
61+
language: 'python',
62+
},
63+
'deep-agents/capabilities/subagents': {
64+
product: 'deep-agents',
65+
section: 'core-capabilities',
66+
topic: 'subagents',
67+
page: 'overview',
68+
language: 'python',
69+
},
70+
'deep-agents/capabilities/memory': {
71+
product: 'deep-agents',
72+
section: 'core-capabilities',
73+
topic: 'memory',
74+
page: 'overview',
75+
language: 'python',
76+
},
77+
'deep-agents/capabilities/skills': {
78+
product: 'deep-agents',
79+
section: 'core-capabilities',
80+
topic: 'skills',
81+
page: 'overview',
82+
language: 'python',
83+
},
84+
'runtimes/getting-started/introduction': {
85+
product: 'runtimes',
86+
section: 'getting-started',
87+
topic: 'overview',
88+
page: 'overview',
89+
language: 'python',
90+
},
91+
'runtimes/aws-strands/overview': {
92+
product: 'runtimes',
93+
section: 'core-capabilities',
94+
topic: 'aws-strands',
95+
page: 'overview',
96+
language: 'python',
97+
},
98+
'runtimes/aws-strands/quickstart': {
99+
product: 'runtimes',
100+
section: 'core-capabilities',
101+
topic: 'aws-strands',
102+
page: 'overview',
103+
language: 'python',
104+
},
105+
'runtimes/aws-strands/how-it-connects': {
106+
product: 'runtimes',
107+
section: 'core-capabilities',
108+
topic: 'aws-strands',
109+
page: 'overview',
110+
language: 'python',
111+
},
112+
'runtimes/microsoft-agent-framework/overview': {
113+
product: 'runtimes',
114+
section: 'core-capabilities',
115+
topic: 'microsoft-agent-framework',
116+
page: 'overview',
117+
language: 'python',
118+
},
119+
'runtimes/microsoft-agent-framework/quickstart': {
120+
product: 'runtimes',
121+
section: 'core-capabilities',
122+
topic: 'microsoft-agent-framework',
123+
page: 'overview',
124+
language: 'python',
125+
},
126+
'runtimes/microsoft-agent-framework/how-it-connects': {
127+
product: 'runtimes',
128+
section: 'core-capabilities',
129+
topic: 'microsoft-agent-framework',
130+
page: 'overview',
131+
language: 'python',
132+
},
133+
// The Mastra demo's backend is a Node AG-UI service, but the Cockpit route
134+
// is `python` like every other manifest entry — the language segment names
135+
// the Cockpit lane, not the runtime.
136+
'runtimes/mastra/overview': {
137+
product: 'runtimes',
138+
section: 'core-capabilities',
139+
topic: 'mastra',
140+
page: 'overview',
141+
language: 'python',
142+
},
143+
'runtimes/mastra/quickstart': {
144+
product: 'runtimes',
145+
section: 'core-capabilities',
146+
topic: 'mastra',
147+
page: 'overview',
148+
language: 'python',
149+
},
150+
'runtimes/mastra/how-it-connects': {
151+
product: 'runtimes',
152+
section: 'core-capabilities',
153+
topic: 'mastra',
154+
page: 'overview',
155+
language: 'python',
156+
},
15157
'langgraph/guides/streaming': {
16158
product: 'langgraph',
17159
section: 'core-capabilities',
@@ -77,6 +219,8 @@ const toAnalyticsLibrary = (library: string): AnalyticsLibrary => {
77219
case 'render':
78220
case 'chat':
79221
case 'ag-ui':
222+
case 'deep-agents':
223+
case 'runtimes':
80224
return library;
81225
default:
82226
return 'unknown';

0 commit comments

Comments
 (0)