# @flutchai/chat-core 中文文档

规范地址：https://npmcn.com/package/%40flutchai/chat-core/

版本：0\.1\.9
npm 元数据更新时间：2026-11-03T08:37:43.088Z
中文译文更新时间：2026-11-15T03:20:52.620Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40flutchai/chat-core
原文对照：https://npmcn.com/package/%40flutchai/chat-core/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：68.9 kB，25 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=18
- 运行依赖：2 个
- 首次发布：2026-10-20T19:23:28.295Z
- 最新版本发布：2026-11-03T08:37:42.633Z
- 近 30 天下载量：2268（2026-10-15 至 2026-11-13，npm 官方下载统计）
- 已发布版本数：11（近 12 个月 11 个）

## 中文简介

Flutch Calch API的框架不可知客户端和状态:请求,SSE流,对话存储和存储. 没有UI.

## 安装

```sh
npm install @flutchai/chat-core
```

也可以使用：`pnpm add @flutchai/chat-core`、`yarn add @flutchai/chat-core`、`bun add @flutchai/chat-core`

## README

# @flutchai/聊天核心

Flutch Chat API的框架-不可知客户端和状态:打出请求,SSE流,对话状态和存储. 没有UI。 说对了 [@flutchai/聊天反应](https://npmcn.com/package/%40flutchai/chat-react/README.md) 或建立自己的接口.

```ts
import { createFlutchClient, createChatStore } from "@flutchai/chat-core";

const client = createFlutchClient({ baseUrl: "/api/chat", agentId: "…" }); // your backend knows the user;
const store = createChatStore({ client });

store.subscribe(s => render(s.messages));
store.getState().setDraftText("Hello");
await store.getState().send();
```

没有商店,直接使用客户端: `invoke`, (中文(简体) ), `stream` (类型事件), `send` (累积文本), `cancel`, (中文(简体) ), `listThreads`, (中文(简体) ), `getMessages`, (中文(简体) ), `react`, (中文(简体) ), `upload`, (中文(简体) ), `getArticle` (作为《京都议定书》缔约方会议的 `article_link`。 API 类型 `@flutchai/chat-contract`。 。 。 .

存储:通过 `storage` (单位:千美元)`get/set/remove`,同步或同步)改为 `createChatStore` 用于反应原生,饼干等. 默认是 `localStorage` 记忆回落.

## 后端代理服务器

**永远不要从浏览器中调用 Flutch API .** API密钥识别出你的公司 您的后端接收浏览器的请求, 添加密钥和用户, 并转发它们 。 客户端镜像 [外部 API](https://npmcn.com/apidoc.md) 路径 `baseUrl`,所以代理是一个薄的通过:

| 浏览器调用 `{baseUrl}` + 键 | 转发至 `https://api.flutch.ai/api/v1` + 键 |
| --- | --- |
| `POST /agents/{agentId}/stream` | 相同的路径, SSE |
| `POST /agents/{agentId}/invoke` | 相同的路径 |
| `POST /agents/{agentId}/cancel` | 相同的路径 |
| `GET /agents/{agentId}/threads` | 相同的路径 |
| `GET /agents/{agentId}/threads/{id}/messages` | 相同的路径 |
| `GET /agents/{agentId}/messages/{id}/stream` | 相同的路径, SSE, 通过 `Last-Event-ID` |
| `PATCH /agents/{agentId}/messages/{id}/reactions` | 相同的路径 |
| `POST /agents/{agentId}/uploads` | 相同路径, 多段 |
| `GET /agents/{agentId}/articles/{id}` | 相同的路径 |

代理对每个请求必须做什么:

1.  **认证浏览器用户** 与你自己的会话.
2.  **设定 `X-API-Key`** 从服务器侧配置.
3.  **设定 `externalUserId` 本身** (JSON身体为 `invoke`编号 :`stream`,其他所有项目的查询字符串),从认证的会话:您自己的id给用户,例如. `(string) $request->user()->id`. Flutch 第一次看到 id 时创建用户,所以没有注册或存储的内容. 永远不要相信一个 `externalUserId` 或者说 `userId` 由浏览器发送,或者一个用户可以读取另一个的对话.
4.  **只允许您想要的代理** 内 `{agentId}`,只有以上路线.
5.  **无缓冲流** 对于两个SSE路线,并给他们一个很长的时间(15分钟):一个运行其他特工的答案需要几分钟. 恢复路线上的404使聊天放弃了仍在生成的回覆.
6.  **前进 `cancel` 仅用于停止按钮.** 关闭页面或失去网络的用户不会停止回复:Flutch完成并保存在线程中,历史终点返回后全部返回. 客户打电话 `cancel` 仅当用户按住 Stop.

### 草图

```php
// routes/api.php
Route::middleware('auth')->prefix('chat/agents/{agent}')->group(function () {
    Route::post('stream', [FlutchProxy::class, 'stream']);
    Route::post('invoke', [FlutchProxy::class, 'invoke']);
    Route::post('cancel', [FlutchProxy::class, 'cancel']);
    Route::get('threads', [FlutchProxy::class, 'threads']);
    Route::get('threads/{thread}/messages', [FlutchProxy::class, 'messages']);
    Route::patch('messages/{message}/reactions', [FlutchProxy::class, 'react']);
});

class FlutchProxy
{
    private const BASE = 'https://api.flutch.ai/api/v1';

    private function http(string $agent)
    {
        abort_unless($agent === config('services.flutch.agent_id'), 404);
        return Http::withHeaders(['X-API-Key' => config('services.flutch.key')]);
    }

    private function userId(Request $r): string
    {
        return (string) $r->user()->id;   // your own id, from your session, never from the request
    }

    private function json($res)
    {
        return response($res->body(), $res->status())->header('Content-Type', 'application/json');
    }

    public function stream(Request $r, string $agent)
    {
        $body = $r->only(['content', 'threadId', 'metadata']) + ['externalUserId' => $this->userId($r)];
        $upstream = $this->http($agent)->withOptions(['stream' => true])
            ->post(self::BASE."/agents/$agent/stream", $body);

        return response()->stream(function () use ($upstream) {
            $body = $upstream->toPsrResponse()->getBody();
            while (!$body->eof() && !connection_aborted()) {
                echo $body->read(1024);
                @ob_flush();
                flush();
            }
            $body->close();   // does not stop the reply: Flutch finishes it and saves it in the thread
        }, $upstream->status(), [
            'Content-Type' => 'text/event-stream',
            'Cache-Control' => 'no-cache',
            'X-Accel-Buffering' => 'no',   // nginx
        ]);
    }

    public function invoke(Request $r, string $agent)
    {
        $body = $r->only(['content', 'threadId', 'metadata']) + ['externalUserId' => $this->userId($r)];
        return $this->json($this->http($agent)->post(self::BASE."/agents/$agent/invoke", $body));
    }

    public function cancel(Request $r, string $agent)
    {
        return $this->json($this->http($agent)->post(
            self::BASE."/agents/$agent/cancel?externalUserId=".urlencode($this->userId($r)),
            $r->only(['requestId'])
        ));
    }

    public function threads(Request $r, string $agent)
    {
        return $this->json($this->http($agent)->get(
            self::BASE."/agents/$agent/threads",
            $r->only(['page', 'limit']) + ['externalUserId' => $this->userId($r)]
        ));
    }

    public function messages(Request $r, string $agent, string $thread)
    {
        return $this->json($this->http($agent)->get(
            self::BASE."/agents/$agent/threads/$thread/messages",
            $r->only(['page', 'limit']) + ['externalUserId' => $this->userId($r)]
        ));
    }

    public function react(Request $r, string $agent, string $message)
    {
        return $this->json($this->http($agent)->patch(
            self::BASE."/agents/$agent/messages/$message/reactions?externalUserId=".urlencode($this->userId($r)),
            $r->only(['like'])
        ));
    }
}
```

上传( E)`POST uploads`)是一个多部分的通过: 附加上传的文件 `Http::attach('file', ...)` 和同样的 `externalUserId` 查询字符串.

这是一个起点,而不是测试的滴入代码。 调整错误处理并确保 PHP 输出缓冲( S)`output_buffering=off`, (中文(简体) ), `zlib.output_compression=off`),任何倒置代理都不缓冲 `/stream` 反应.

## 常见问题

### @flutchai/chat-core 是什么？

Flutch Calch API的框架不可知客户端和状态:请求,SSE流,对话存储和存储\. 没有UI\.

### 如何安装 @flutchai/chat-core？

在项目目录运行 npm install @flutchai/chat-core，或使用 pnpm add / yarn add / bun add。

### @flutchai/chat-core 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @flutchai/chat-core 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @flutchai/chat-core 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @flutchai/chat-core 可以商用吗？

@flutchai/chat-core 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @flutchai/chat-core 的下载量有多少？

根据 npm 官方下载统计，@flutchai/chat-core 在 2026/10/15 – 2026/11/13 这 30 天内被下载 2,268 次，日均约 76 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @flutchai/chat-core 还在维护吗？

最新版本 0\.1\.9 发布于 2026/11/03（12 天前）；至今共发布 11 个版本，其中过去 12 个月发布了 11 个；首次发布于 2026/10/21。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

