Package Exports
- @coston/agent/mcp
- @coston/agent/persistence
- @coston/agent/react
- @coston/agent/server
Readme
@coston/agent
Reusable, standards-first agent-chat for app-scoped LLM copilots. A thin wiring layer over the Vercel AI SDK and MCP — not a framework. Each app keeps its own agent, scoped to its own API; this package removes the copy-paste.
- Why
- Subpath exports
- Install
- Releases
@coston/agent/server— chat route- Develop
- Adopting in a new app? → USAGE.md · Design rationale → ARCHITECTURE.md
Why
Apps that embed an LLM copilot keep re-growing the same chat plumbing: the
streamText → toUIMessageStreamResponse → useChat route, provider resolution +
API-key encryption, conversation persistence, the chat panel, and an MCP server.
This package is that shared core; each app injects what's app-specific — tools,
system prompt, auth, and persistence.
Subpath exports
| Import | What it gives you |
|---|---|
@coston/agent/server |
createChatRoute, createProviderResolver/buildModel, secret crypto, the model registry, defineAgent |
@coston/agent/react |
ChatPanel/ChatSession/MessageBubble, ProviderForm, createLocalTransport |
@coston/agent/persistence |
PersistenceAdapter + createPrismaPersistence |
@coston/agent/mcp |
createMcpRoute, createScopedHelper, mcpText |
Server, persistence, and mcp are server-only; only react ships to the browser.
The model registry and provider-label helpers (MODELS_BY_PROVIDER,
DEFAULT_MODEL, providerNeedsKey, providerDisplayName, shortModelName, …)
are re-exported from both /server and /react for building settings UIs; the
exported types are the reference.
Adopting in a new app? See USAGE.md — a complete, generic recipe (prerequisites, the required data model, and wiring all four subpaths).
Install
npm install @coston/agentRequires Node >=20. Peer deps resolve from the consuming app, and most are
optional — pulled only by the subpath that uses them. Always required: ai,
@ai-sdk/anthropic, @ai-sdk/openai. Optional, by subpath: @ai-sdk/react,
react, react-dom, @coston/ui (>=0.3.0 <0.5.0), lucide-react,
streamdown for /react; mcp-handler, @modelcontextprotocol/sdk for /mcp;
@ai-sdk/openai-compatible for the browser local transport. See
USAGE.md §1 for the exact set.
Releases
Automated by semantic-release. On push to main, the GitHub Actions workflow
type-checks, tests, builds, bumps the SemVer version from the Conventional-Commit
history, publishes to npm, tags vX.Y.Z, and cuts a GitHub Release. Use
fix: / feat: / feat!: commit prefixes to drive patch / minor / major bumps.
(dist/ is a build artifact — rebuilt in CI and shipped in the npm tarball, not
committed to git.)
The GitHub Releases page is the changelog — each release lists the changes generated from the commit history.
@coston/agent/server — chat route
// app/api/chat/route.ts
import { createChatRoute, createProviderResolver, decryptSecret } from '@coston/agent/server';
const { resolveUserModel } = createProviderResolver({
loadSetting: userId => db.aiProviderSetting.findUnique({ where: { userId } }),
decrypt: decryptSecret,
});
export const { POST } = createChatRoute({
authorize: async (req, body) => {
/* app owns ALL auth — return { userId, scope, context } or { error, status } */
},
resolveModel: resolveUserModel,
buildTools: ({ context }) => buildAppTools(context), // standard AI SDK ToolSet
buildSystemPrompt: ({ context, body }) => buildPrompt(context, body),
persistence, // or: saveMessages: ({ conversationId, scope, messages }) => …
conversationIdFrom: body => body.conversationId,
maxSteps: 12,
});The same ToolSet works for both actuation styles: tools with execute run
server-side; tools without execute are surfaced to the browser via
useChat's onToolCall. The package never names a tool.
Agent definition (defineAgent)
Define an agent from Markdown instructions, a tool set, and Skills — Markdown
playbooks pulled on demand via an auto-injected load_skill tool (progressive
disclosure):
import { defineAgent } from '@coston/agent/server';
import instructions from './agent/instructions.md'; // app loads the markdown
const agent = defineAgent({
instructions, // Markdown
tools: ctx => buildAppTools(ctx), // standard AI SDK ToolSet (or a plain ToolSet)
skills: [{ name: 'example', description: 'When this applies', content: exampleMd }],
approvals: ['delete_item'], // → AI SDK needsApproval; UI renders Approve/Deny
context: ctx => snapshot(ctx),
});
// in createChatRoute:
buildTools: ({ context }) => agent.tools(context),
buildSystemPrompt: ({ context }) => agent.systemPrompt(context),Skills add only name/description to the prompt; the body loads on demand.
Develop
npm install
npm run build # tsdown → dist/ (ESM, externalized peers, stable d.ts names)
npm test # vitest
npm run type-check
npm run lintLicense
MIT