agent_kit 0.1.2
agent_kit: ^0.1.2 copied to clipboard
Drop-in Flutter widgets for AI agent UIs — tool-call cards, thinking bubbles, citation chips, plan-progress timelines. Backend-agnostic. shadcn-for-agents.
agent_kit #
Drop-in Flutter widgets for the non-text parts of AI agent UIs — tool-call cards, thinking bubbles, citation chips, plan-progress timelines. Backend-agnostic. shadcn-for-agents.
The chat-UI market is crowded. The layer above chat — visualizing what
the model is doing — is wide open. agent_kit fills that gap.
AgentView(stream: agent.events)
That's the entire integration. Stream AgentEvents, get a Cursor /
Perplexity-style agent panel for free.
Install #
dependencies:
agent_kit: ^0.1.0
flutter pub get
30-second usage #
import 'package:agent_kit/agent_kit.dart';
import 'package:flutter/material.dart';
class AnswerPanel extends StatelessWidget {
const AnswerPanel({super.key, required this.events});
final Stream<AgentEvent> events;
@override
Widget build(BuildContext context) {
return AgentKitThemeScope(
theme: AgentKitTheme.fromColorScheme(Theme.of(context).colorScheme),
child: AgentView(stream: events),
);
}
}
Emit any of the four event kinds from your LLM client and AgentView renders
the right widget for each:
controller.add(const ThinkingEvent(ThinkingStep(text: '…', isStreaming: true)));
controller.add(const ToolCallEvent(ToolCall(
id: 'tc-1', name: 'search_web', state: ToolCallState.running,
args: {'q': 'flutter'},
)));
controller.add(const CitationEvent([
Citation(sourceId: 's1', title: 'flutter.dev', url: 'https://flutter.dev'),
]));
controller.add(const PlanEvent([
PlanStep(id: 'p1', label: 'Search', state: PlanStepState.running),
PlanStep(id: 'p2', label: 'Synthesize'),
]));
What you get #
| Widget | What it renders |
|---|---|
ToolCallCard |
Collapsible card with state icon, args (pretty-printed JSON), result preview, error + retry slot. |
ToolCallFeed |
Vertical feed of cards, keyed by ToolCall.id so streaming updates don't churn. |
ThinkingBubble |
Claude / o1-style "Thinking…" bubble with pulsing dot and auto-collapse. |
ReasoningTrace |
Collapsible numbered reasoning log. |
CitationChip |
Perplexity-style numbered inline badge. |
CitationCard |
Rich source card — favicon, host, title, snippet. |
CitationList |
Horizontal scrollable strip of citation cards. |
PlanProgress |
Vertical stepper with live state transitions and nested sub-steps. |
AgentTimeline |
Chronological mix of every event kind. |
AgentView |
Stream-in, widgets-out. The five-line integration. |
AgentEventBuilder |
Low-level builder hook for full layout control. |
Every widget honors AgentKitTheme and ships with light + dark defaults
derived from the ambient Material 3 ColorScheme.
Why agent_kit #
agent_kit |
flutter_ai_toolkit |
Rolling your own | |
|---|---|---|---|
| Tool-call lifecycle UI | ✅ | ❌ | weeks |
| Thinking / reasoning UX | ✅ | ❌ | days |
| Citation widgets | ✅ | ❌ | days |
| Plan / step progress | ✅ | ❌ | days |
| Backend-agnostic | ✅ | ✅ | n/a |
| Stable widget keys (no element churn) | ✅ | partial | manual |
| Material 3 theming | ✅ | ✅ | manual |
| Streaming-safe state machine | ✅ | n/a | manual |
flutter_ai_toolkit covers the chat surface (messages, typing indicators,
attachments). agent_kit covers the surface above chat — agent
introspection. The two compose cleanly.
Custom tool renderers #
Every other widget is themed; for the long tail of tool calls (image generation, maps, charts) register a custom renderer once:
ToolRenderer.register('generate_image', (context, call) {
final url = call.result as String?;
return url == null
? const SizedBox.shrink()
: Image.network(url);
});
ToolCallCard uses the registered builder when call.name matches and falls
back to its default args/result preview otherwise.
Recipes #
Use with streamdown #
The two packages were designed to compose. Stream the final markdown answer
with streamdown below your
AgentView:
Column(
children: [
AgentView(stream: agent.events),
Streamdown(stream: agent.tokens),
],
)
Bring your own state #
Use AgentEventBuilder instead of AgentView when you need a custom
layout (sidebar + main, two-column, etc.):
AgentEventBuilder(
stream: agent.events,
builder: (context, events) => Row(
children: [
Expanded(child: AnswerColumn(events: events)),
Sidebar(events: events),
],
),
)
Wire to MCP #
agent_kit's AgentEvent types map 1:1 to MCP tool-call and reasoning
primitives. The companion package mcp_client (ships Sep 2026) wires this
end-to-end.
Example #
A full Cursor-style replay lives in example/ — run
it on iOS, Android, web, macOS, Windows, or Linux:
cd example
flutter run
Quality #
- 55 unit + widget tests, all green
flutter analyzewith strict casts / inference / raw-types — zero issues- Zero runtime dependencies on AI provider SDKs
- Stable widget keys per event id — no element churn on streaming updates
RepaintBoundaryon every card
License #
BSD-3-Clause. Copyright © 2026 Jayu Limbani.