@pdhaku0/gemini-cli-agent-sdk
v0.1.5
Published
A high-level SDK for building AI Agent chat interfaces using Gemini ACP
Readme
Agent Chat SDK
A TypeScript SDK for building chat UIs on top of the Gemini CLI Agent via ACP (Agent Chat Protocol). It provides a browser-safe client, a bridge for the CLI, and a UI-friendly event model.
Features
- WebSocket transport with reconnect + ACP framing
- Client event model tuned for UI rendering
- Tool call parsing (permissions, inputs, diff rendering)
- Replay support for late joiners / infinite scroll
- Bridge process to run Gemini CLI via stdio
- Optional store (
AgentChatStore) for React/GUI state
Compatibility
From the ACP refresh support added in this SDK version onward, the client performs ACP initialize during connect() and the bridge starts Gemini CLI with --acp by default.
This is a breaking compatibility change for older Gemini CLI / ACP implementations that only support the legacy --experimental-acp flow or do not implement initialize.
- Compatible target: Gemini CLI builds with modern ACP support, including
initialize - Legacy fallback for bridge launch only: set
GEMINI_ACP_FLAG=--experimental-acp - Note: even with the legacy flag, the SDK client still expects ACP
initialize, so older protocol implementations may not work end-to-end
Installation
npm install @pdhaku0/gemini-cli-agent-sdkRequirements
- Node.js 18+ (bridge and any server usage)
- Gemini CLI with modern ACP support and
--acp - Browser client or Node with
ws
The SDK now targets the current ACP flow described in Gemini CLI ACP Mode documentation, including ACP initialize.
- Expected target: modern Gemini CLI releases with ACP
initializesupport - Legacy Gemini CLI builds that only support the old
--experimental-acpflow may not work - Minimum compatible Gemini CLI version is not pinned yet
Quick Start
1) Start the bridge
npm run start:bridgeBy default this enables SYS tag capture and emits bridge/structured_event.
You can control it with:
SYS_TAG_MODE=raw npm run start:bridge # disable capture
SYS_TAG_MODE=both npm run start:bridge # keep tags + emit events2) Connect a client
import { AgentChatClient } from '@pdhaku0/gemini-cli-agent-sdk/client';
const client = new AgentChatClient({
url: 'ws://localhost:4444',
cwd: '/path/to/project',
replay: { limit: 15 },
});
client.on('text_delta', ({ delta }) => process.stdout.write(delta));
client.on('tool_update', ({ toolCall }) => {
console.log(`[tool] ${toolCall.name} ${toolCall.status}`);
});
await client.connect();
await client.sendMessage('List files in the current directory.');connect() now performs the ACP initialize handshake before creating or reusing a session.
You can also enumerate and reload ACP sessions:
const sessions = await client.listSessions();
await client.loadSession(sessions[0].sessionId);
await client.loadSession(sessions[0].sessionId, { replay: { limit: 20 } });3) Replay older turns (infinite scroll)
const older = await AgentChatClient.fetchReplay('ws://localhost:4444', {
before: oldestTimestampMs,
limit: 10,
});
client.prependMessages(older);4) Optional SYS tags (structured capture)
Use SYS tags in assistant output and capture them on the bridge:
import { GeminiBridge } from '@pdhaku0/gemini-cli-agent-sdk/server';
import { createSysTagTransform } from '@pdhaku0/gemini-cli-agent-sdk/extras';
const bridge = new GeminiBridge({
outgoingTransform: createSysTagTransform({ mode: 'event' }),
});
bridge.start();5) Hidden initial prompt
await client.sendMessage('System priming...', { hidden: 'turn' });Examples
examples/next-app— full Next.js App Router UI (auth, approvals, replay, session persistence)examples/cli— minimal Node CLI (streaming + tool approvals)
Examples are kept in the repo but excluded from npm to keep the package lean.
Documentation
docs/USAGE.md— full end-to-end guidedocs/API.md— API surfacedocs/EVENTS.md— event model + rendering rulesdocs/INTEGRATION.md— Next/Node integration patternsdocs/TROUBLESHOOTING.md— common pitfalls
Development
- Build:
npm run build - Bridge:
npm run start:bridge - CLI example:
node examples/cli/index.js
Notes
- The bridge keeps in-memory replay only. Restarting the bridge clears replay history.
- Reusing sessions across reloads is supported by passing a saved
sessionIdto the client. - Replay
limitis turns, not messages.
