Skip to content

Commit 89d24f9

Browse files
bloveclaude
andauthored
feat(brand): polish @ngaf/langgraph + @ngaf/ag-ui READMEs; add cockpit OG image (#294)
Closes two loose ends from the post-merge sweep punchlist. @ngaf/langgraph README: - was: title + one-liner + only-citations section (35 lines, sparse for npmjs.com) - now: matches @ngaf/render shape from D.1 — intro paragraph, install + peer deps, "What it does" capability bullets, quick-start example (provideAgent + agent()), injection-context gotcha callout, citations example, doc links, license. @ngaf/ag-ui README: - was already substantive (49 lines with usage + citations) - adds Install section, expands one-liner to mention compatible runtimes (LangGraph / CrewAI / Mastra / etc.), Part-of line, Documentation links footer, License. @ngaf/licensing README intentionally left alone — explicitly marked "Private, pre-1.0. Not intended as a standalone import." apps/cockpit/src/app/opengraph-image.tsx — new: - 1200×630 PNG share card matching cockpit's Linear-style devtools aesthetic (Phase 8). Inter Bold headline (no Garamond — saves a 500KB TTF bundle and matches cockpit's in-app typography). - Eyebrow "COCKPIT · ANGULAR AGENT FRAMEWORK", headline "The live reference app for the framework.", subhead describing the four modes, footer renders the actual ModeSwitcher pill pattern (Run/Code/Docs/API with Run active) + cockpit.cacheplane.ai wordmark. - runtime='edge' (no local font files to read). apps/cockpit/src/app/layout.tsx — metadata expanded with proper openGraph + twitter blocks so the new image gets picked up on shares. All cockpit e2e tests pass; lint reports 0 errors (21 pre-existing warnings). Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent be97bc9 commit 89d24f9

4 files changed

Lines changed: 269 additions & 14 deletions

File tree

apps/cockpit/src/app/layout.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,19 @@ import { cssVars } from '@ngaf/ui-react';
33
import './cockpit.css';
44

55
export const metadata = {
6-
title: 'Cockpit',
7-
description: 'Integrated cockpit for manifest-driven developer reference demos.',
6+
title: 'Cockpit — Angular Agent Framework',
7+
description: 'The live reference app for the Angular Agent Framework. Real LangGraph + AG-UI agents through the Angular surface you’ll ship.',
8+
openGraph: {
9+
title: 'Cockpit — Angular Agent Framework',
10+
description: 'The live reference app for the framework. Real LangGraph + AG-UI agents through the same Angular surface you’ll ship.',
11+
type: 'website',
12+
siteName: 'Cockpit',
13+
},
14+
twitter: {
15+
card: 'summary_large_image',
16+
title: 'Cockpit — Angular Agent Framework',
17+
description: 'The live reference app for the framework. Real LangGraph + AG-UI agents through the Angular surface you’ll ship.',
18+
},
819
};
920

1021
interface RootLayoutProps {
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/**
2+
* Default OpenGraph + Twitter share card for the cockpit reference app.
3+
*
4+
* Renders a 1200×630 PNG at request time via Next.js ImageResponse.
5+
* Per-route overrides can be added by dropping an `opengraph-image.tsx`
6+
* file in any route folder (e.g. per-product or per-topic cards).
7+
*
8+
* Cockpit's chrome is Linear-style devtools (Phase 8 spec) — Inter Bold
9+
* for the headline rather than the marketing site's EB Garamond, so we
10+
* don't need to bundle a serif TTF.
11+
*/
12+
import { ImageResponse } from 'next/og';
13+
14+
export const runtime = 'edge';
15+
export const alt = 'Cockpit — the live reference app for the Angular Agent Framework';
16+
export const size = { width: 1200, height: 630 };
17+
export const contentType = 'image/png';
18+
19+
async function loadFont(family: string, weight: number): Promise<ArrayBuffer | null> {
20+
try {
21+
const css = await fetch(
22+
`https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}:wght@${weight}&display=swap`,
23+
{ headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36' } },
24+
).then((res) => res.text());
25+
const match = css.match(/src:\s*url\((https?:\/\/[^)]+)\)/);
26+
if (!match) return null;
27+
const fontRes = await fetch(match[1]);
28+
if (!fontRes.ok) return null;
29+
return await fontRes.arrayBuffer();
30+
} catch {
31+
return null;
32+
}
33+
}
34+
35+
export default async function OpenGraphImage() {
36+
const [interRegular, interBold, monoBold] = await Promise.all([
37+
loadFont('Inter', 400),
38+
loadFont('Inter', 600),
39+
loadFont('JetBrains+Mono', 700),
40+
]);
41+
const fonts = [
42+
interRegular && { name: 'Inter', data: interRegular, weight: 400 as const, style: 'normal' as const },
43+
interBold && { name: 'Inter', data: interBold, weight: 700 as const, style: 'normal' as const },
44+
monoBold && { name: 'JetBrains Mono', data: monoBold, weight: 700 as const, style: 'normal' as const },
45+
].filter((f): f is NonNullable<typeof f> => f !== null);
46+
47+
return new ImageResponse(
48+
(
49+
<div
50+
style={{
51+
width: '100%',
52+
height: '100%',
53+
background: '#f4f6fb',
54+
display: 'flex',
55+
flexDirection: 'column',
56+
padding: '64px 72px',
57+
color: '#1a1a2e',
58+
fontFamily: 'Inter, sans-serif',
59+
}}
60+
>
61+
{/* Eyebrow */}
62+
<div
63+
style={{
64+
fontFamily: 'JetBrains Mono, monospace',
65+
fontSize: 16,
66+
letterSpacing: '0.12em',
67+
color: '#004090',
68+
fontWeight: 700,
69+
textTransform: 'uppercase',
70+
marginBottom: 24,
71+
}}
72+
>
73+
Cockpit · Angular Agent Framework
74+
</div>
75+
76+
{/* Headline — Inter Bold (cockpit chrome is sans-serif Linear-style) */}
77+
<div
78+
style={{
79+
fontSize: 68,
80+
lineHeight: 1.08,
81+
fontWeight: 700,
82+
letterSpacing: '-0.02em',
83+
color: '#1a1a2e',
84+
marginBottom: 22,
85+
maxWidth: 1000,
86+
}}
87+
>
88+
The live reference app for the framework.
89+
</div>
90+
91+
{/* Subhead */}
92+
<div
93+
style={{
94+
fontSize: 24,
95+
lineHeight: 1.5,
96+
color: '#555770',
97+
maxWidth: 940,
98+
marginBottom: 'auto',
99+
}}
100+
>
101+
Real LangGraph and AG-UI agents running through the same Angular surface you&apos;ll ship.
102+
Switch between Run · Code · Docs · API for each capability.
103+
</div>
104+
105+
{/* Mode pills + cockpit wordmark */}
106+
<div
107+
style={{
108+
display: 'flex',
109+
alignItems: 'center',
110+
justifyContent: 'space-between',
111+
marginTop: 32,
112+
}}
113+
>
114+
<div style={{ display: 'flex', gap: 10 }}>
115+
{['Run', 'Code', 'Docs', 'API'].map((mode, i) => (
116+
<ModePill key={mode} active={i === 0}>{mode}</ModePill>
117+
))}
118+
</div>
119+
<div
120+
style={{
121+
display: 'flex',
122+
alignItems: 'center',
123+
gap: 10,
124+
fontFamily: 'JetBrains Mono, monospace',
125+
fontSize: 18,
126+
fontWeight: 700,
127+
color: '#1a1a2e',
128+
}}
129+
>
130+
<span style={{ fontSize: 26 }}>🛩️</span>
131+
<span>cockpit.cacheplane.ai</span>
132+
</div>
133+
</div>
134+
</div>
135+
),
136+
{
137+
...size,
138+
fonts,
139+
},
140+
);
141+
}
142+
143+
interface ModePillProps {
144+
active: boolean;
145+
children: React.ReactNode;
146+
}
147+
148+
/** Mimics the cockpit mode-switcher: rounded pill, accent on the active one. */
149+
function ModePill({ active, children }: ModePillProps) {
150+
return (
151+
<div
152+
style={{
153+
display: 'flex',
154+
alignItems: 'center',
155+
padding: '8px 20px',
156+
borderRadius: 999,
157+
background: active ? '#004090' : '#ffffff',
158+
border: `1px solid ${active ? '#004090' : '#e6e8ee'}`,
159+
color: active ? '#ffffff' : '#555770',
160+
fontFamily: 'JetBrains Mono, monospace',
161+
fontSize: 15,
162+
fontWeight: 700,
163+
}}
164+
>
165+
{children}
166+
</div>
167+
);
168+
}

libs/ag-ui/README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
# @ngaf/ag-ui
22

3-
Adapter that wraps an [AG-UI](https://github.com/ag-ui-protocol/ag-ui) `AbstractAgent` into the runtime-neutral `Agent` contract from `@ngaf/chat`.
3+
Adapter that wraps an [AG-UI](https://github.com/ag-ui-protocol/ag-ui) `AbstractAgent` into the runtime-neutral `Agent` contract from `@ngaf/chat`. Works with any AG-UI-compatible backend — LangGraph, CrewAI, Mastra, Microsoft Agent Framework, AG2, Pydantic AI, AWS Strands, CopilotKit runtime.
4+
5+
Part of the [Angular Agent Framework](https://github.com/cacheplane/angular-agent-framework). MIT licensed.
6+
7+
## Install
8+
9+
```bash
10+
npm install @ngaf/ag-ui @ngaf/chat @ag-ui/client
11+
```
12+
13+
## Quick start
414

515
```ts
616
import { provideAgUiAgent, AG_UI_AGENT } from '@ngaf/ag-ui';
@@ -46,3 +56,13 @@ The `bridgeCitationsState()` function populates `Message.citations` from AG-UI S
4656
```
4757

4858
Each citation object in the array supports `id`, `index`, `title`, `url`, `snippet`, and custom `extra` fields. The messageId key matches the corresponding message in the chat history.
59+
60+
## Documentation
61+
62+
- [Quickstart](https://cacheplane.ai/docs/agent/getting-started/quickstart)
63+
- [AG-UI adapter guide](https://cacheplane.ai/docs/chat/guides/writing-an-adapter)
64+
- [AG-UI protocol](https://github.com/ag-ui-protocol/ag-ui)
65+
66+
## License
67+
68+
MIT — free for any use. See [LICENSE](../../LICENSE).

libs/langgraph/README.md

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,65 @@
11
# @ngaf/langgraph
22

3-
Adapter that wraps a LangGraph agent into the runtime-neutral `Agent` contract from `@ngaf/chat`.
3+
Adapter that wraps a LangGraph agent into the runtime-neutral `Agent` contract from `@ngaf/chat`. The Angular equivalent of LangGraph's React `useStream()` hook — signal-driven access to messages, status, tool calls, interrupts, subagents, regenerate, and thread history.
44

5-
## Citations
5+
Part of the [Angular Agent Framework](https://github.com/cacheplane/angular-agent-framework). MIT licensed.
66

7-
The `extractCitations()` function populates `Message.citations` from LangGraph message metadata. It reads from `additional_kwargs.citations` (preferred) or `additional_kwargs.sources` (fallback).
7+
## Install
88

9-
### Example: RAG chain with citations
9+
```bash
10+
npm install @ngaf/langgraph @ngaf/chat
11+
```
12+
13+
**Peer dependencies:** `@angular/core ^20.0.0 || ^21.0.0`, `@langchain/core ^1.1.0`, `@langchain/langgraph-sdk ^1.7.0`, `rxjs ~7.8.0`
14+
15+
## What it does
16+
17+
- **`agent()`** — Angular Signal-based handle to a LangGraph streaming run. Returns `messages()`, `status()`, `isLoading()`, `error()`, `interrupt()`, `toolCalls()`, plus actions (`submit`, `stop`, `regenerate`, `reload`).
18+
- **`provideAgent()`** — configure the LangGraph endpoint once in `app.config.ts`. Per-call overrides are accepted by `agent()` itself.
19+
- **Thread persistence** — pass `threadId: signal(...)` + `onThreadId` to round-trip thread IDs through your own storage (localStorage, URL, etc.).
20+
- **`MockAgentTransport`** — deterministic in-memory transport for tests. Never mock `agent()` itself; swap the transport instead.
21+
- **`extractCitations()`** — populates `Message.citations` from LangGraph message metadata. Reads from `additional_kwargs.citations` (preferred) or `additional_kwargs.sources` (fallback).
22+
23+
## Quick start
24+
25+
```ts
26+
// app.config.ts
27+
import { provideAgent } from '@ngaf/langgraph';
28+
29+
export const appConfig: ApplicationConfig = {
30+
providers: [
31+
provideAgent({
32+
apiUrl: 'https://your-langgraph-platform.com',
33+
assistantId: 'my-agent',
34+
}),
35+
],
36+
};
37+
```
1038

1139
```ts
12-
import { additional_kwargs } from '@langchain/core/messages';
40+
// chat.component.ts
41+
import { Component } from '@angular/core';
42+
import { agent } from '@ngaf/langgraph';
43+
import { ChatComponent } from '@ngaf/chat';
1344

45+
@Component({
46+
imports: [ChatComponent],
47+
template: `<chat [agent]="chat" />`,
48+
})
49+
export class ChatComponentHost {
50+
chat = agent({ assistantId: 'my-agent' });
51+
}
52+
```
53+
54+
> `agent()` must be called within an Angular injection context (component field initializer or constructor). Calling it in `ngOnInit` or any async context throws `NG0203: inject() must be called from an injection context`.
55+
56+
## Citations example
57+
58+
```ts
1459
// In your LangGraph node:
1560
const response = await llm.invoke([...]);
1661

17-
// Attach citations metadata:
18-
const messageWithCitations = new AIMessage({
62+
return new AIMessage({
1963
content: response.content,
2064
additional_kwargs: {
2165
citations: [
@@ -24,11 +68,23 @@ const messageWithCitations = new AIMessage({
2468
index: 1,
2569
title: 'Example Article',
2670
url: 'https://example.com/article',
27-
snippet: 'Relevant excerpt...'
28-
}
29-
]
30-
}
71+
snippet: 'Relevant excerpt...',
72+
},
73+
],
74+
},
3175
});
3276

3377
// Message.citations auto-populates in @ngaf/chat via extractCitations()
3478
```
79+
80+
## Documentation
81+
82+
- [Quickstart](https://cacheplane.ai/docs/agent/getting-started/quickstart)
83+
- [`agent()` API reference](https://cacheplane.ai/docs/agent/api/agent)
84+
- [Human-in-the-loop / interrupts](https://cacheplane.ai/docs/agent/guides/interrupts)
85+
- [Thread persistence](https://cacheplane.ai/docs/agent/guides/persistence)
86+
- [Testing with `MockAgentTransport`](https://cacheplane.ai/docs/agent/guides/testing)
87+
88+
## License
89+
90+
MIT — free for any use. See [LICENSE](../../LICENSE).

0 commit comments

Comments
 (0)