npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@stello-ai/server

v0.2.2

Published

Stello server — PG-backed multi-user multi-space service layer

Readme

@stello-ai/server

Stello 的服务化层。基于 PostgreSQL 持久化,通过 REST(Hono)和 WebSocket 暴露 @stello-ai/core 的全部能力。

核心约束:一个 space = 一个 StelloAgent = 一棵 session 树。


快速开始

1. 启动 PostgreSQL

docker compose up -d   # 使用仓库内的 docker-compose.yml

2. 创建 Server

import pg from 'pg'
import { createStelloServer } from '@stello-ai/server'

const pool = new pg.Pool({ connectionString: 'postgresql://stello:stello@localhost:5432/stello' })

const server = await createStelloServer({
  pool,
  agentPoolOptions: {
    buildConfig: (ctx) => ({
      // capabilities: 提供 lifecycle / tools / skills / confirm
      // session: 提供 sessionResolver / consolidateFn
      // 详见 @stello-ai/core 的 StelloAgentConfig
      capabilities: { /* ... */ },
      session: {
        sessionResolver: async (sessionId) => { /* ... */ },
        consolidateFn: async (currentMemory, messages) => { /* ... */ },
      },
    }),
    idleTtlMs: 5 * 60 * 1000, // 空闲 5 分钟驱逐 agent
  },
})

const { port, close } = await server.listen(3000)
console.log(`Stello server running on port ${port}`)

3. 调用 API

# 创建用户(直接写数据库,server 不提供注册接口)
# INSERT INTO users (api_key, name) VALUES ('my-api-key', 'Alice');

# 创建 Space
curl -X POST http://localhost:3000/spaces \
  -H "X-API-Key: my-api-key" \
  -H "Content-Type: application/json" \
  -d '{"label": "My Space", "systemPrompt": "You are helpful."}'

认证

所有 REST 和 WS 请求都需要 X-API-Key header。

Server 从 users 表校验 API key,提取 userId,再校验 space 所有权。

| 状态码 | 含义 | |--------|------| | 401 | API key 缺失或无效 | | 403 | Space 不属于当前用户 | | 404 | Space 或 Session 不存在 |


REST API

Space 管理

POST /spaces — 创建 Space

创建时自动创建 root session(role=main)。

请求体:

{
  "label": "My Space",
  "systemPrompt": "You are helpful.",    // 可选
  "consolidatePrompt": "Summarize."      // 可选
}

响应 201

{
  "id": "uuid",
  "userId": "uuid",
  "label": "My Space",
  "systemPrompt": "You are helpful.",
  "consolidatePrompt": "Summarize.",
  "config": {},
  "createdAt": "2026-03-24T...",
  "updatedAt": "2026-03-24T..."
}

GET /spaces — 列出 Spaces

返回当前用户的所有 spaces。

响应 200Space[]

GET /spaces/:spaceId — Space 详情

响应 200Space

PATCH /spaces/:spaceId — 更新 Space

可更新字段:labelsystemPromptconsolidatePrompt

更新 systemPrompt 时会同步写入 root session 的 session_data,无需重启 agent。

请求体:

{
  "label": "New Name",
  "systemPrompt": "Updated prompt"
}

响应 200:更新后的 Space

DELETE /spaces/:spaceId — 删除 Space

级联删除所有 sessions、records、session_data。同时从 AgentPool 驱逐缓存的 agent。

响应 204:无 body


Session 操作

GET /spaces/:spaceId/sessions — 列出 Sessions

返回 space 下所有 sessions(core SessionMeta 格式,含 parentId、children、refs、depth 等树结构信息)。

响应 200SessionMeta[]

[
  {
    "id": "uuid",
    "parentId": null,
    "children": ["uuid-1", "uuid-2"],
    "refs": [],
    "label": "Root",
    "index": 0,
    "scope": null,
    "status": "active",
    "depth": 0,
    "turnCount": 0,
    "metadata": {},
    "tags": [],
    "createdAt": "...",
    "updatedAt": "...",
    "lastActiveAt": "..."
  }
]

GET /spaces/:spaceId/sessions/:id — Session 详情

响应 200SessionMeta

GET /spaces/:spaceId/sessions/:id/messages — 对话记录

返回 session 的 L3 对话历史(TurnRecord 格式)。

响应 200TurnRecord[]

[
  { "role": "user", "content": "hello", "timestamp": "..." },
  { "role": "assistant", "content": "hi there", "timestamp": "...", "metadata": { "model": "..." } }
]

POST /spaces/:spaceId/sessions/:id/turn — 非流式对话

REST 降级路径。适用于不需要流式输出的场景。

请求体:

{ "input": "What is Stello?" }

响应 200EngineTurnResult

POST /spaces/:spaceId/sessions/:id/fork — Fork Session

从指定 session 创建子分支。

请求体:

{ "label": "Sub Topic", "scope": "coding" }

响应 201:新创建的 SessionMeta

POST /spaces/:spaceId/sessions/:id/archive — 归档 Session

将 session 状态设为 archived

响应 200{ sessionId: string }


WebSocket API

连接

ws://host/spaces/:spaceId/ws

连接时通过 X-API-Key header 认证(在 WebSocket upgrade 请求中设置)。

const ws = new WebSocket('ws://localhost:3000/spaces/{spaceId}/ws', {
  headers: { 'X-API-Key': 'my-api-key' },
})

每个 WS 连接绑定一个 space。同一连接上同一时刻只能 enter 一个 session。

客户端 → 服务端

所有消息均为 JSON 格式。

session.enter — 进入 Session

{ "type": "session.enter", "sessionId": "uuid" }

服务端执行 attachSession + enterSession,返回 bootstrap 数据。

session.message — 非流式对话

{ "type": "session.message", "input": "What is Stello?" }

需要先 session.enter,否则返回 NOT_ENTERED 错误。

session.stream — 流式对话

{ "type": "session.stream", "input": "Explain in detail." }

服务端逐 chunk 推送 stream.delta,完成后推送 stream.end

session.fork — Fork

{ "type": "session.fork", "options": { "label": "Sub Topic", "scope": "coding" } }

session.leave — 离开 Session

{ "type": "session.leave" }

服务端执行 leaveSession + detachSession

服务端 → 客户端

session.entered

{ "type": "session.entered", "sessionId": "uuid", "bootstrap": { "context": {...}, "session": {...} } }

turn.complete

{ "type": "turn.complete", "result": { /* EngineTurnResult */ } }

stream.delta

{ "type": "stream.delta", "chunk": "partial text..." }

stream.end

{ "type": "stream.end", "result": { /* EngineTurnResult */ } }

session.forked

{ "type": "session.forked", "child": { /* SessionMeta */ } }

session.left

{ "type": "session.left", "sessionId": "uuid" }

error

{ "type": "error", "message": "Not in a session", "code": "NOT_ENTERED" }

错误码:

| code | 含义 | |------|------| | PARSE_ERROR | 消息不是合法 JSON | | UNKNOWN_TYPE | 未知的消息类型 | | NOT_ENTERED | 未 enter session 就发送需要 session 的操作 | | ALREADY_ENTERED | 已在 session 中,需先 leave | | HANDLER_ERROR | 处理器内部错误 |

断连行为

客户端断开 WS 连接时,服务端只执行 detachSession(不执行 leaveSession)。engine runtime 通过 runtimeRecyclePolicy 自然回收。


典型流程

REST: 创建 Space → 对话

POST /spaces              → 创建 space(自动创建 root session)
GET  /spaces/:id/sessions → 拿到 root session id
POST /spaces/:id/sessions/:rootId/turn → 发消息
GET  /spaces/:id/sessions/:rootId/messages → 读历史

WS: 实时对话

WS /spaces/:id/ws                           → 建立连接
→ { type: "session.enter", sessionId }       → 进入 session
← { type: "session.entered", bootstrap }     → 收到 bootstrap
→ { type: "session.stream", input }          → 流式对话
← { type: "stream.delta", chunk }            → 逐 chunk 收到
← { type: "stream.delta", chunk }
← { type: "stream.end", result }             → 对话完成
→ { type: "session.fork", options }          → fork 子分支
← { type: "session.forked", child }
→ { type: "session.leave" }                  → 离开
← { type: "session.left", sessionId }

编程接口

除了 HTTP/WS,所有内部组件也可直接使用:

import {
  // Server 入口
  createStelloServer,

  // 存储适配器
  PgSessionStorage,     // SessionStorage 实现
  PgMainStorage,        // MainStorage 实现(extends above)
  PgSessionTree,        // SessionTree 实现
  PgMemoryEngine,       // MemoryEngine 实现

  // 数据库
  createPool,           // pg.Pool 工厂
  migrate,              // 执行 SQL 迁移

  // Space 管理
  SpaceManager,         // Space CRUD
  AgentPool,            // per-space StelloAgent 缓存

  // WebSocket
  ConnectionManager,    // WS 连接态管理

  // 类型
  type Space,
  type SpaceConfig,
  type StelloServerOptions,
  type StelloServer,
  type AgentPoolOptions,
  type ConnectionState,
  type PoolOptions,
} from '@stello-ai/server'

数据库

Server 使用 PostgreSQL,7 张表:

| 表 | 用途 | |----|------| | users | API key 认证 | | spaces | Space 配置 | | sessions | Session 元数据(core + session 包共用) | | records | L3 对话记录 | | session_data | 统一槽位(system_prompt / insight / memory / scope / index) | | session_refs | 跨分支引用 | | core_data | Space 级全局键值 |

首次启动时 createStelloServer() 自动执行迁移(可通过 skipMigrate: true 跳过)。