mirror of
https://github.com/vercel/chat.git
synced 2026-09-14 18:32:29 +08:00
d2ffcc2cbe
We've acquired `chat` on npm. This plan covers renaming all packages and setting up automated publishing.
| Current Name | New Name | Version |
|--------------|----------|---------|
| `chat-sdk` | `chat` | 4.0.0 |
| `@chat-sdk/slack` | `@chat-adapter/slack` | 4.0.0 |
| `@chat-sdk/gchat` | `@chat-adapter/gchat` | 4.0.0 |
| `@chat-sdk/teams` | `@chat-adapter/teams` | 4.0.0 |
| `@chat-sdk/state-memory` | `@chat-adapter/state-memory` | 4.0.0 |
| `@chat-sdk/state-redis` | `@chat-adapter/state-redis` | 4.0.0 |
| `@chat-sdk/state-ioredis` | `@chat-adapter/state-ioredis` | 4.0.0 |
1. **Main package** (`packages/chat-sdk/package.json`):
- Change `"name": "chat-sdk"` → `"name": "chat"`
- Change `"version": "0.1.0"` → `"version": "4.0.0"`
2. **Adapter packages**:
- `packages/adapter-slack/package.json`: `@chat-sdk/slack` → `@chat-adapter/slack`
- `packages/adapter-gchat/package.json`: `@chat-sdk/gchat` → `@chat-adapter/gchat`
- `packages/adapter-teams/package.json`: `@chat-sdk/teams` → `@chat-adapter/teams`
- Update all versions to `4.0.0`
- Update dependency on `chat-sdk` → `chat`
3. **State packages**:
- `packages/state-memory/package.json`: `@chat-sdk/state-memory` → `@chat-adapter/state-memory`
- `packages/state-redis/package.json`: `@chat-sdk/state-redis` → `@chat-adapter/state-redis`
- `packages/state-ioredis/package.json`: `@chat-sdk/state-ioredis` → `@chat-adapter/state-ioredis`
- Update all versions to `4.0.0`
- Update dependency on `chat-sdk` → `chat`
Update `peerDependencies` and `dependencies` in each package:
```json
// Before
"peerDependencies": {
"chat-sdk": "workspace:*"
}
// After
"peerDependencies": {
"chat": "workspace:*"
}
```
Search and replace across the codebase:
| Find | Replace |
|------|---------|
| `from "chat-sdk"` | `from "chat"` |
| `from 'chat-sdk'` | `from 'chat'` |
| `import("chat-sdk")` | `import("chat")` |
| `from "@chat-sdk/slack"` | `from "@chat-adapter/slack"` |
| `from "@chat-sdk/gchat"` | `from "@chat-adapter/gchat"` |
| `from "@chat-sdk/teams"` | `from "@chat-adapter/teams"` |
| `from "@chat-sdk/state-memory"` | `from "@chat-adapter/state-memory"` |
| `from "@chat-sdk/state-redis"` | `from "@chat-adapter/state-redis"` |
| `from "@chat-sdk/state-ioredis"` | `from "@chat-adapter/state-ioredis"` |
Update any references to old package names in:
- `pnpm-workspace.yaml`
- `turbo.json` (task filters)
- Root `package.json` scripts
1. **README.md files** in each package
2. **Examples** (`examples/nextjs-chat/`)
3. **AGENTS.md** and other docs
4. **JSDoc comments** referencing package names
1. **Install changesets**:
```bash
pnpm add -D @changesets/cli
pnpm changeset init
```
2. **Configure `.changeset/config.json`**:
```json
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [
["chat", "@chat-adapter/*"]
],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["example-nextjs-chat"]
}
```
3. **Add GitHub Action** (`.github/workflows/release.yml`):
```yaml
name: Release
on:
push:
branches:
- main
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- run: pnpm build
- run: pnpm test
- name: Create Release Pull Request or Publish
uses: changesets/action@v1
with:
publish: pnpm changeset publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
```
4. **Add publish config to each package.json**:
```json
"publishConfig": {
"access": "public"
}
```
1. Run full build: `pnpm build`
2. Run typecheck: `pnpm typecheck`
3. Run lint: `pnpm lint`
4. Run tests: `pnpm test`
5. Test local linking in example app
| File | Changes |
|------|---------|
| `packages/chat-sdk/package.json` | Rename to `chat`, version 4.0.0 |
| `packages/adapter-slack/package.json` | Rename to `@chat-adapter/slack`, update deps |
| `packages/adapter-gchat/package.json` | Rename to `@chat-adapter/gchat`, update deps |
| `packages/adapter-teams/package.json` | Rename to `@chat-adapter/teams`, update deps |
| `packages/state-memory/package.json` | Rename to `@chat-adapter/state-memory`, update deps |
| `packages/state-redis/package.json` | Rename to `@chat-adapter/state-redis`, update deps |
| `packages/state-ioredis/package.json` | Rename to `@chat-adapter/state-ioredis`, update deps |
| `examples/nextjs-chat/package.json` | Update all dependencies |
| `packages/integration-tests/package.json` | Update all dependencies |
| `turbo.json` | Update package references |
| All `*.ts` files | Update import statements |
| All `README.md` files | Update package names in docs |
| `.changeset/config.json` | Create new |
| `.github/workflows/release.yml` | Create new |
1. Update all `package.json` files (names, versions, dependencies)
2. Run `pnpm install` to update lockfile
3. Update all import statements in source files
4. Update all import statements in test files
5. Update documentation
6. Set up changesets
7. Run full validation
8. Create initial changeset for 4.0.0 release
9. Commit and push
If issues arise:
1. Git revert the rename commit
2. Run `pnpm install` to restore lockfile
3. Previous npm versions remain available
4.2 KiB
4.2 KiB
Overview
We are building an abstraction library, similar to an ORM for databases, that allows me to program applicatons that interact with chat systems like Slack, Microsoft Teams, Google Chat, and Discord.
The primary use case are AI agents that help users of the chat app.
Goals
- Programming language: TypeScript
- For very common tasks I should be able to write a program that doesn't care about whether the user is using Slack, Teams, etc.
- First-class support for listening to new @-mentions (first time mention in a thread) and then following subsequent messages in the thread
- For very advanced formatting, an escape hatch is fine, but it should be rarely used.
- Serverless compatibility. Should work with @vercel/slack-bolt for Slack and have a higher level API compatible with it.
- Compatibility with modern web frameworks for the webhooks (Next.js, Hono, etc.)
- Built-in ability to "lock a thread" which ensures that only one instance of the bot replies at a time even if multiple webhooks fire in short order (using e.g. the Redis state handler)
Functionality
- Listening to all new threads or messages in a channel. Optionally, subscribing to all future messages in a thread
- Listening to new @-mentions in any message in a subscribed channel
- Ability to post to a thread
- Ability to make new threads
- Ability to unsubscribe from threads
Implementation / Architecture
- I assume that all these chat apps have an API that is basically
- A way to send messages, new thread or into a threa
- Receive a webhook with new messages
- But I have not researched this. Some may just give you all messages, some may have matchers.
- There should be a common interface that the end user of our library program and an adapter directory with one entry for Slack, Teams, etc. that implements it.
Pseudo code
This isn't the final API, just me thinking of what would be nice.
Setting up the bot
[lib/bot.ts]
import {Chat} from "chat";
import {Bold} from "chat/jsx-runtime";
import {SlackAdapter} from "@chat-adapter/slack";
import {TeamsAdapter} from "@chat-adapter/teams";
import {GoogleChatAdapter} from "@chat-adapter/gchat";
import {createRedisState} from "@chat-adapter/state-redis";
export const bot = new Chat({
userName: "mybot" // @mybot in Slack, Teams, etc.
adapters: {
slack: new SlackAdapter({
secret: …
}),
teams: new TeamsAdapter({
secret: …
}),
google: new GoogleChatAdapter({
userName: "awesomeBot", // Called @awesomeBot on Google
secret: …
}),
},
conversationState: createRedisState()
});
// Threads are default-locked to this instance while callbacks run
bot.onNewMention(async (thread, message) => {
await thread.subscribe();
await thread.post("Thanks for adding me");
});
bot.onNewMessage(/topic/, (thread, message) => {
await thread.subscribe();
await thread.post("Thanks for adding me");
});
bot.onSubscribedMessage(async (thread, newMessage) => {
const reply = myAgent.generate({
recentMessages: thread.recentMessages,
newMessage
});
thread.post(`**Agent** response: ${reply}`);
})
Interfaces
interface Thread {
recentMessages: Message[];
allMessages: AsyncIteractor<Message>;
subscribe: (thread: Thread, latestMessage: Message) => Promise<void>;
unsubscribe: () => Promise<unknown>;
post: (message: string | FormattedMessage) => Promise<void>;
// Make recentMessages reflect the current state
refresh: () => Promise<void>;
}
interface Message {
text: string;
formatted: FormattedMessage;
author: {
userName: string; // handle for @-mention
fullName: string;
userId: string; // Unique ID
isBot: false | true | "unknown";
isMe: boolean; // Whether the message was sent by this bot
};
metadata: {
dateSent: Date; // and other metadata
};
}
One WebHook route per adapter
[app / api / webhooks / slack / route.ts];
import { bot } from "@/lib/bot";
export const POST = bot.webhooks.slack;
[app / api / webhooks / teams / route.ts];
import { bot } from "@/lib/bot";
export const POST = bot.webhooks.teams;
[app / api / webhooks / google / route.ts];
import { bot } from "@/lib/bot";
export const POST = bot.webhooks.google;