Skip to content

Commit dc32a40

Browse files
committed
docs(showcase/spring-ai): region markers across 13 cells
Per-framework region pass on spring-ai. 13 cells advanced from B (regions missing) to A (ready). Same patterns as mastra (CopilotKit#4326), smalls batch 1 (CopilotKit#4361), ms-agent (CopilotKit#4363), and google-adk (CopilotKit#4369). Cells covered (28 regions): - agentic-chat: provider-setup + configure-suggestions in-place; chat-component sibling - chat-customization-css: css-variables (theme.css) + theme-css-import - chat-slots: register-welcome-slot + register-disclaimer-slot + register-assistant-message-slot - frontend-tools: frontend-tool-handler + frontend-tool-registration - headless-simple: use-agent-simple + message-list-simple sibling (production carries deduplicateMessages QA logic against the AG-UI Spring AI adapter's multi-run tool-call loop) - open-gen-ui: minimal-provider-setup + minimal-runtime-flag (route.ts) - open-gen-ui-advanced: advanced-runtime-config (route.ts, shared file with open-gen-ui) - prebuilt-popup: popup-basic-setup - prebuilt-sidebar: sidebar-basic-setup + sidebar-configuration - readonly-state-agent-context: context-provider-sketch + use-agent-context-call - shared-state-read-write: use-agent-read + use-agent-write (page.tsx) + notes-card-render + preferences-card-render - subagents: delegation-log-frontend (frontend) + subagent-setup + supervisor-delegation-tools (Java backend, SubagentsController.java already in highlight) - a2ui-fixed-schema: backend-render-operations on tools/DisplayFlightTool.java Sibling teaching files (Java backend, distinct from Python/TS frameworks): - agentic-chat/chat-component.snippet.tsx — production Chat carries QA hooks (useFrontendTool / useRenderTool / useAgentContext + data-testid) irrelevant to the prebuilt-chat docs page - headless-simple/headless-chat.snippet.tsx — production carries deduplicateMessages defensive logic; sibling exposes a clean useAgent + agent.messages.map teaching surface Deferred: - a2ui-fixed-schema::backend-schema-json-load — spring-ai keeps the schema inline as Java List.of(Map.of(...)) in DisplayFlightTool.java rather than loading from a JSON file. Same divergence as ms-agent-dotnet (CopilotKit#4363); the docs region's "load JSON at startup" framing doesn't match. - declarative-gen-ui::runtime-inject-tool — cross-cutting; tracked in PDX-70. Backend region markers use Java syntax `// @region[name]` / `// @endregion[name]`. Test plan: - [ ] `npx tsx showcase/scripts/bundle-demo-content.ts` succeeds; all 28 regions resolve in `demo-content.json` (verified locally — re-audit shows only deferred items remaining) - [ ] localhost shell-docs spot-check `/spring-ai/prebuilt-components/chat` — chat-component snippet renders the minimal Chat from the sibling file - [ ] localhost shell-docs spot-check `/spring-ai/headless/simple` — use-agent-simple + message-list-simple resolve from the sibling file (no dedup noise in the docs surface) - [ ] localhost shell-docs spot-check `/spring-ai/multi-agent/subagents` — delegation-log-frontend + subagent-setup + supervisor-delegation-tools resolve; backend snippet shows spring-ai's idiom (ToolCallback factory + ChatClient.builder) rather than langgraph's @tool/create_agent pattern - [ ] localhost shell-docs spot-check `/spring-ai/state/shared-state-read-write` — all four regions resolve including the multi-file pair from notes-card.tsx + preferences-card.tsx - [ ] localhost shell-docs spot-check `/spring-ai/generative-ui/a2ui/fixed-schema` — backend-render-operations resolves; backend-schema-json-load remains yellow (deferred per above)
1 parent cbf2766 commit dc32a40

18 files changed

Lines changed: 239 additions & 0 deletions

File tree

showcase/integrations/spring-ai/src/app/api/copilotkit-ogui/route.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,24 @@ export const POST = async (req: NextRequest) => {
3636
const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
3737
endpoint: "/api/copilotkit-ogui",
3838
serviceAdapter: new ExperimentalEmptyAdapter(),
39+
// @region[minimal-runtime-flag]
40+
// @region[advanced-runtime-config]
41+
// Server-side config is identical for the minimal and advanced cells —
42+
// the advanced behaviour (sandbox -> host function calls) is wired
43+
// entirely on the frontend via `openGenerativeUI.sandboxFunctions` on
44+
// the provider. The single `openGenerativeUI` flag below turns on
45+
// Open Generative UI for the listed agent(s); the runtime middleware
46+
// converts each agent's streamed `generateSandboxedUi` tool call into
47+
// `open-generative-ui` activity events.
3948
runtime: new CopilotRuntime({
4049
// @ts-ignore -- see main route.ts
4150
agents,
4251
openGenerativeUI: {
4352
agents: ["open-gen-ui", "open-gen-ui-advanced"],
4453
},
4554
}),
55+
// @endregion[advanced-runtime-config]
56+
// @endregion[minimal-runtime-flag]
4657
});
4758
return await handleRequest(req);
4859
} catch (error: unknown) {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Docs-only snippet — not imported or rendered. The actual route is served
2+
// by page.tsx, which carries QA hooks (frontend tools, render tools, agent
3+
// context) that aren't relevant to the prebuilt-chat docs page. This file
4+
// gives the docs a minimal Chat definition to point at via the
5+
// chat-component region without disturbing the runtime demo.
6+
//
7+
// Why a sibling file: the bundler walks every file in the demo folder and
8+
// extracts region markers from each, so a docs-targeted teaching example
9+
// can live alongside the production demo without being wired into the
10+
// route. See: showcase/scripts/bundle-demo-content.ts.
11+
12+
import {
13+
CopilotChat,
14+
useConfigureSuggestions,
15+
} from "@copilotkit/react-core/v2";
16+
17+
// @region[chat-component]
18+
export function Chat() {
19+
useConfigureSuggestions({
20+
suggestions: [
21+
{ title: "Write a sonnet", message: "Write a short sonnet about AI." },
22+
],
23+
available: "always",
24+
});
25+
26+
return <CopilotChat agentId="agentic_chat" className="h-full rounded-2xl" />;
27+
}
28+
// @endregion[chat-component]

showcase/integrations/spring-ai/src/app/demos/agentic-chat/page.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ import { z } from "zod";
1313

1414
export default function AgenticChatDemo() {
1515
return (
16+
// @region[provider-setup]
1617
<CopilotKit runtimeUrl="/api/copilotkit" agent="agentic_chat">
1718
<Chat />
1819
</CopilotKit>
20+
// @endregion[provider-setup]
1921
);
2022
}
2123

@@ -68,6 +70,7 @@ function Chat() {
6870
},
6971
});
7072

73+
// @region[configure-suggestions]
7174
useConfigureSuggestions({
7275
suggestions: [
7376
{
@@ -81,6 +84,7 @@ function Chat() {
8184
],
8285
available: "always",
8386
});
87+
// @endregion[configure-suggestions]
8488

8589
return (
8690
<div

showcase/integrations/spring-ai/src/app/demos/chat-customization-css/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99

1010
import React from "react";
1111
import { CopilotKit, CopilotChat } from "@copilotkit/react-core/v2";
12+
// @region[theme-css-import]
1213
import "./theme.css";
14+
// @endregion[theme-css-import]
1315

1416
export default function ChatCustomizationCssDemo() {
1517
return (

showcase/integrations/spring-ai/src/app/demos/chat-customization-css/theme.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* https://docs.copilotkit.ai/custom-look-and-feel/customize-built-in-ui-components
77
*/
88

9+
/* @region[css-variables] */
10+
/* CopilotKit CSS variable overrides (accent colors, etc.) */
911
.chat-css-demo-scope {
1012
--copilot-kit-primary-color: #ff006e;
1113
--copilot-kit-contrast-color: #ffffff;
@@ -16,6 +18,7 @@
1618
--copilot-kit-separator-color: #ff006e;
1719
--copilot-kit-muted-color: #c2185b;
1820
}
21+
/* @endregion[css-variables] */
1922

2023
.chat-css-demo-scope .copilotKitMessages {
2124
font-family: "Georgia", "Cambria", "Times New Roman", serif;

showcase/integrations/spring-ai/src/app/demos/chat-slots/page.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,18 @@ function Chat() {
3232
available: "always",
3333
});
3434

35+
// @region[register-welcome-slot]
3536
const welcomeScreen = CustomWelcomeScreen;
37+
// @endregion[register-welcome-slot]
38+
// @region[register-disclaimer-slot]
3639
const input = { disclaimer: CustomDisclaimer };
40+
// @endregion[register-disclaimer-slot]
41+
// @region[register-assistant-message-slot]
3742
const messageView = {
3843
assistantMessage:
3944
CustomAssistantMessage as unknown as typeof CopilotChatAssistantMessage,
4045
};
46+
// @endregion[register-assistant-message-slot]
4147

4248
return (
4349
<CopilotChat

showcase/integrations/spring-ai/src/app/demos/frontend-tools/page.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ function Chat() {
2222
"var(--copilot-kit-background-color)",
2323
);
2424

25+
// @region[frontend-tool-registration]
2526
useFrontendTool({
2627
name: "change_background",
2728
description:
@@ -31,14 +32,17 @@ function Chat() {
3132
.string()
3233
.describe("The CSS background value. Prefer gradients."),
3334
}),
35+
// @region[frontend-tool-handler]
3436
handler: async ({ background }: { background: string }) => {
3537
setBackground(background);
3638
return {
3739
status: "success",
3840
message: `Background changed to ${background}`,
3941
};
4042
},
43+
// @endregion[frontend-tool-handler]
4144
});
45+
// @endregion[frontend-tool-registration]
4246

4347
useConfigureSuggestions({
4448
suggestions: [
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Docs-only snippet — not imported or rendered. The actual route is served
2+
// by page.tsx, which carries a `deduplicateMessages` pass to defend against
3+
// the Spring AI AG-UI adapter's multi-run tool-call loop (see the comment
4+
// on that helper in page.tsx). That dedup logic is QA scaffolding, not part
5+
// of the headless-chat teaching content. This file gives the docs a clean
6+
// minimal surface to point at via `use-agent-simple` and
7+
// `message-list-simple` regions without the dedup distraction.
8+
//
9+
// Why a sibling file: the bundler walks every file in the demo folder and
10+
// extracts region markers from each, so a docs-targeted teaching example
11+
// can live alongside the production demo without being wired into the
12+
// route. See: showcase/scripts/bundle-demo-content.ts.
13+
14+
import React, { useState } from "react";
15+
import {
16+
useAgent,
17+
useComponent,
18+
useCopilotKit,
19+
useRenderToolCall,
20+
} from "@copilotkit/react-core/v2";
21+
import { z } from "zod";
22+
23+
function ShowCard({ title, body }: { title: string; body: string }) {
24+
return (
25+
<div className="my-2 rounded-lg border border-gray-300 bg-white p-4 shadow-sm">
26+
<div className="font-semibold text-gray-900">{title}</div>
27+
<div className="mt-1 text-sm text-gray-700 whitespace-pre-wrap">
28+
{body}
29+
</div>
30+
</div>
31+
);
32+
}
33+
34+
export function HeadlessChat() {
35+
// @region[use-agent-simple]
36+
const { agent } = useAgent({ agentId: "headless-simple" });
37+
const { copilotkit } = useCopilotKit();
38+
const [input, setInput] = useState("");
39+
40+
useComponent({
41+
name: "show_card",
42+
description: "Display a titled card with a short body of text.",
43+
parameters: z.object({
44+
title: z.string().describe("Short heading for the card."),
45+
body: z.string().describe("Body text for the card."),
46+
}),
47+
render: ShowCard,
48+
});
49+
50+
const renderToolCall = useRenderToolCall();
51+
// @endregion[use-agent-simple]
52+
53+
const send = () => {
54+
const text = input.trim();
55+
if (!text || agent.isRunning) return;
56+
agent.addMessage({
57+
id: crypto.randomUUID(),
58+
role: "user",
59+
content: text,
60+
});
61+
void copilotkit.runAgent({ agent }).catch(() => {});
62+
setInput("");
63+
};
64+
65+
return (
66+
<div className="flex flex-col gap-3">
67+
<div className="flex flex-col gap-2 rounded-xl border border-gray-200 bg-white p-4 min-h-[300px]">
68+
{/* @region[message-list-simple] */}
69+
{agent.messages.length === 0 && (
70+
<div className="text-sm text-gray-400">No messages yet. Say hi!</div>
71+
)}
72+
{agent.messages.map((m) => {
73+
if (m.role === "user") {
74+
return (
75+
<div
76+
key={m.id}
77+
data-message-role="user"
78+
className="self-end rounded-lg bg-blue-600 px-3 py-2 text-white max-w-[80%]"
79+
>
80+
{typeof m.content === "string" ? m.content : ""}
81+
</div>
82+
);
83+
}
84+
if (m.role === "assistant") {
85+
const toolCalls =
86+
"toolCalls" in m && Array.isArray(m.toolCalls) ? m.toolCalls : [];
87+
return (
88+
<div
89+
key={m.id}
90+
data-message-role="assistant"
91+
className="self-start max-w-[90%]"
92+
>
93+
{m.content && (
94+
<div className="rounded-lg bg-gray-100 px-3 py-2 text-gray-900">
95+
{m.content as React.ReactNode}
96+
</div>
97+
)}
98+
{toolCalls.map((tc: { id: string }) => (
99+
<div key={tc.id}>
100+
{renderToolCall({ toolCall: tc as any })}
101+
</div>
102+
))}
103+
</div>
104+
);
105+
}
106+
return null;
107+
})}
108+
{agent.isRunning && (
109+
<div className="text-xs text-gray-400">Agent is thinking...</div>
110+
)}
111+
{/* @endregion[message-list-simple] */}
112+
</div>
113+
<div className="flex gap-2">
114+
<textarea
115+
className="flex-1 rounded-lg border border-gray-300 p-2 text-sm"
116+
rows={2}
117+
value={input}
118+
onChange={(e) => setInput(e.target.value)}
119+
placeholder="Type a message..."
120+
/>
121+
<button
122+
className="rounded-lg bg-blue-600 px-4 py-2 text-white text-sm font-medium disabled:opacity-50"
123+
onClick={send}
124+
disabled={agent.isRunning || !input.trim()}
125+
>
126+
Send
127+
</button>
128+
</div>
129+
</div>
130+
);
131+
}

showcase/integrations/spring-ai/src/app/demos/open-gen-ui/page.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ const minimalSuggestions = [
8484

8585
export default function OpenGenUiDemo() {
8686
return (
87+
// @region[minimal-provider-setup]
88+
// Minimal Open Generative UI frontend: the built-in activity renderer is
89+
// registered by CopilotKitProvider, so a plain <CopilotChat /> is enough —
90+
// no custom tool renderers, no activity-renderer registration.
91+
// We DO pass `openGenerativeUI.designSkill` to swap in visualisation-tuned
92+
// guidance in place of the default shadcn design skill.
8793
<CopilotKit
8894
runtimeUrl="/api/copilotkit-ogui"
8995
agent="open-gen-ui"
@@ -95,6 +101,7 @@ export default function OpenGenUiDemo() {
95101
</div>
96102
</div>
97103
</CopilotKit>
104+
// @endregion[minimal-provider-setup]
98105
);
99106
}
100107

showcase/integrations/spring-ai/src/app/demos/prebuilt-popup/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99

1010
export default function PrebuiltPopupDemo() {
1111
return (
12+
// @region[popup-basic-setup]
1213
<CopilotKit runtimeUrl="/api/copilotkit" agent="prebuilt-popup">
1314
<MainContent />
1415
<CopilotPopup
@@ -20,6 +21,7 @@ export default function PrebuiltPopupDemo() {
2021
/>
2122
<Suggestions />
2223
</CopilotKit>
24+
// @endregion[popup-basic-setup]
2325
);
2426
}
2527

0 commit comments

Comments
 (0)