Agent SkillsTanStack/ai › ai-persistence/server

ai-persistence/server

GitHub

提供服务器端聊天状态持久化中间件,支持消息、运行状态及中断恢复。适用于需多设备同步或耐用性工具审批的场景,确保会话历史在服务器端权威存储与重建。

packages/ai-persistence/skills/ai-persistence/server/SKILL.md TanStack/ai

触发场景

需要跨设备同步聊天历史 实现服务器端运行的持久化与中断恢复 构建具备耐用性工具审批机制的AI服务

安装

npx skills add TanStack/ai --skill ai-persistence/server -g -y
更多选项

非标准路径

npx skills add https://github.com/TanStack/ai/tree/main/packages/ai-persistence/skills/ai-persistence/server -g -y

不安装直接使用

npx skills use TanStack/ai@ai-persistence/server

指定 Agent (Claude Code)

npx skills add TanStack/ai --skill ai-persistence/server -a claude-code -g -y

安装 repo 全部 skill

npx skills add TanStack/ai --all -g -y

预览 repo 内 skill

npx skills add TanStack/ai --list

SKILL.md

Frontmatter
{
    "name": "ai-persistence\/server",
    "type": "sub-skill",
    "library": "tanstack-ai",
    "sources": [
        "TanStack\/ai:docs\/persistence\/chat-persistence.md",
        "TanStack\/ai:docs\/persistence\/overview.md",
        "TanStack\/ai:docs\/persistence\/controls.md"
    ],
    "description": "Server chat state with withPersistence from @tanstack\/ai-persistence. Authoritative transcript, run lifecycle, durable interrupts\/approvals, chatParamsFromRequest, reconstructChat, snapshotStreaming. Use when the server owns history, multi-device, or durable tool approvals. NOT client localStorage (see ai-core\/client-persistence in @tanstack\/ai) and NOT stream reconnect alone.\n",
    "library_version": "0.0.0"
}

Server Chat Persistence

Builds on ai-persistence. Package: @tanstack/ai-persistence.

withPersistence(persistence) is a ChatMiddleware that writes chat state to a backend: messages, runs, interrupts (optional metadata). It does not mutate the chunk stream and does not replace delivery durability.

Setup

import {
  chat,
  chatParamsFromRequest,
  toServerSentEventsResponse,
} from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { withPersistence } from '@tanstack/ai-persistence'
// Your adapter — see ai-persistence/stores.
import { persistence } from './persistence'

export async function POST(request: Request) {
  const params = await chatParamsFromRequest(request)
  const stream = chat({
    adapter: openaiText('gpt-5.5'),
    messages: params.messages,
    threadId: params.threadId,
    runId: params.runId,
    ...(params.resume ? { resume: params.resume } : {}),
    middleware: [withPersistence(persistence)],
  })
  return toServerSentEventsResponse(stream)
}

Always pass threadId and runId from the client (via chatParamsFromRequest / body helpers). Forward resume when the client resolves pending interrupts.

For dev and tests, memoryPersistence() from @tanstack/ai-persistence is a drop-in backend that implements all four stores in process.

What each store does

Store Role Required?
messages Full model-message transcript load/save Yes for withPersistence
runs Run status, timing, usage, errors Optional; needed for interrupt durability
interrupts Pending/resolved tool approvals & waits Optional; requires runs
metadata App-owned namespaced key/value Optional

Named shapes: ChatTranscriptPersistence (floor), ChatPersistence (all four). Annotate your factory with one of these, not with bare AIPersistence — the unparameterized type is the all-optional bag, and withPersistence rejects it because stores.messages is possibly undefined.

Authoritative-history contract

  • Non-empty messages → finish overwrites the stored thread with that array. Post the complete transcript, never a delta.
  • Empty messages → middleware loads the stored thread and continues.

When state is written

Moment Writes Best-effort?
onStart Pending turn snapshot (user + history) Yes — failure does not abort
Interrupt boundary New interrupts, run → interrupted, message snapshot No
onFinish Full transcript first, then run → completed, commit resumes No
Stream (optional) Throttled partial assistant text Yes if snapshotStreaming: true
onError Run → failed Resumes stay pending
onAbort Run → interrupted Resumes stay pending
withPersistence(persistence, {
  snapshotStreaming: true,
  snapshotIntervalMs: 1000, // default
})

Streaming snapshots default off (finish is authoritative). Enable only when partial-output durability is worth extra writes.

Resumes accepted in onConfig commit only at a success boundary (interrupt or finish). A failed run leaves interrupts pending so the same resume batch can retry.

Interrupt / resume flow

  1. Middleware records pending interrupts and gates new input: if pending exist, the request must include a matching resume batch or onConfig throws.
  2. On valid resume, middleware builds resumeToolState and clears config.resume so the engine does not double-reconstruct from client history (server owns transcript).
  3. On success boundary, interrupts are marked resolved/cancelled.

Hydrate a thread for the client (reconstructChat)

Server-authoritative clients load history by threadId (often GET):

import { reconstructChat } from '@tanstack/ai-persistence'

export async function GET(request: Request) {
  return reconstructChat(persistence, request, {
    // Multi-user: required in production
    authorize: async (threadId, req) => {
      const userId = await sessionUserId(req)
      return userOwnsThread(userId, threadId)
    },
  })
}

Returns { messages, activeRun, interrupts }:

  • messages — UI messages for paint
  • activeRun{ runId } if a run is still generating (runs.findActiveRun)
  • interrupts — pending human-in-the-loop state for re-prompt

Without authorize, anyone who guesses ?threadId= gets the transcript.

Generation activities

withGenerationPersistence(persistence) tracks run records for non-chat activities (image, audio, TTS, video, transcription). Do not fake threadId = requestId on chat run stores — use the generation helper.

Common mistakes

CRITICAL: Posting a message delta as messages

Wipes the stored thread down to that delta. Always send full history or [].

HIGH: Omitting threadId / runId

Persistence keys and resume need stable ids. Use chatParamsFromRequest.

HIGH: Interrupts without runs

interrupts requires runs; withPersistence throws otherwise.

HIGH: Typing a factory as bare AIPersistence

AIPersistence defaults to the sparse all-optional bag, so withPersistence and reconstructChat reject the value. Return ChatPersistence (or ChatTranscriptPersistence) instead.

MEDIUM: Expecting withPersistence to reconnect a dropped stream

That is delivery durability (resumable streams), not state persistence.

Cross-references

  • ai-persistence — layers and recommended stack
  • ai-persistence/stores — implement the store interfaces
  • ai-core/client-persistence (@tanstack/ai) — browser half
  • ai-core/locks — multi-instance coordination

版本历史

  • 05280a5 当前 2026-07-30 23:52

同 Skill 集合

.claude/skills/gap-analysis/SKILL.md
packages/ai-code-mode/skills/ai-code-mode/SKILL.md
packages/ai-mcp/skills/ai-mcp/SKILL.md
packages/ai-memory/skills/tanstack-ai-memory-hindsight/SKILL.md
packages/ai-memory/skills/tanstack-ai-memory-honcho/SKILL.md
packages/ai-memory/skills/tanstack-ai-memory-in-memory/SKILL.md
packages/ai-memory/skills/tanstack-ai-memory-mem0/SKILL.md
packages/ai-memory/skills/tanstack-ai-memory-redis/SKILL.md
packages/ai-memory/skills/tanstack-ai-memory/SKILL.md
packages/ai-persistence/skills/ai-persistence/build-cloudflare-adapter/SKILL.md
packages/ai-persistence/skills/ai-persistence/build-cloudflare-artifact-store/SKILL.md
packages/ai-persistence/skills/ai-persistence/build-custom-adapter/SKILL.md
packages/ai-persistence/skills/ai-persistence/build-drizzle-adapter/SKILL.md
packages/ai-persistence/skills/ai-persistence/build-prisma-adapter/SKILL.md
packages/ai-persistence/skills/ai-persistence/SKILL.md
packages/ai-persistence/skills/ai-persistence/stores/SKILL.md
packages/ai/skills/ai-core/ag-ui-protocol/SKILL.md
packages/ai/skills/ai-core/chat-experience/SKILL.md
packages/ai/skills/ai-core/custom-backend-integration/SKILL.md
packages/ai/skills/ai-core/debug-logging/SKILL.md
packages/ai/skills/ai-core/locks/SKILL.md
packages/ai/skills/ai-core/middleware/SKILL.md
packages/ai/skills/ai-core/SKILL.md
packages/ai/skills/ai-core/tool-calling/SKILL.md
.claude/skills/triage-github/SKILL.md
packages/ai-sandbox/skills/ai-sandbox/SKILL.md
packages/ai/skills/ai-core/adapter-configuration/SKILL.md
packages/ai/skills/ai-core/client-persistence/SKILL.md
packages/ai/skills/ai-core/media-generation/SKILL.md
packages/ai/skills/ai-core/structured-outputs/SKILL.md

元信息

文件数
0
版本
1cb04d5
Hash
935839ff
收录时间
2026-07-30 23:52

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-01 14:25
浙ICP备14020137号-1 $访客地图$