TypeScript Vercel AI Over Unix Domain Sockets

This guide starts from TypeScript Response Recording and Resumption. The application code stays the same. Only the Memory Service transport changes.

Local Memory Service

Note: The memory-service CLI has not yet been released as a standalone binary. You can install it from source with Go:

go install -tags "sqlite_fts5 sqlite_json" github.com/chirino/memory-service@latest
memory-service serve \
  --db-kind=sqlite \
  --db-url=file:$HOME/.local/share/memory-service/memory.db \
  --vector-kind=sqlite \
  --cache-kind=local \
  --unix-socket=$HOME/.local/run/memory-service/api.sock

Those flags keep the TypeScript example local and low-friction: SQLite handles both stored records and vector search, cache-kind=local avoids a separate cache service, the database file sits under $HOME/.local/share, and the Unix socket sits under $HOME/.local/run so it benefits from the user’s home-directory permissions rather than a shared /tmp location.

Agent Configuration

No TypeScript source file needs a host or socket change. The checkpoint already calls the package helpers without transport-specific wiring in the app:

app.ts
  res.setHeader("Connection", "keep-alive");

  try {
    await withMemoryService(
      {
        ...memoryServiceConfig,
        conversationId,
        authorization,
        memoryContentType: "vercelai",
        historyContentType: "history/vercelai",
        userText: userMessage,

Update the file that sets environment variables before node dist/app.js or tsx src/app.ts starts. If you keep those in a .env file next to the app, this .env.example snippet shows the exact value to add:

.env.example
MEMORY_SERVICE_UNIX_SOCKET=$HOME/.local/run/memory-service/api.sock

The package will route both fetch-based REST requests and the response-recorder gRPC client over that socket.

function get-token() {
  curl -sSfX POST http://localhost:8081/realms/memory-service/protocol/openid-connect/token \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "client_id=memory-service-client" \
    -d "client_secret=change-me" \
    -d "grant_type=password" \
    -d "username=bob" \
    -d "password=bob" \
    | jq -r '.access_token'
}

Start a streaming response, but disconnect before it finishes:

curl -NsSfX POST http://localhost:9090/chat/7aa65d1d-ec04-46d7-b0cc-6bf6f96ca4b7 \
  --max-time 0.15 \
  -H "Content-Type: text/plain" \
  -H "Authorization: Bearer $(get-token)" \
  -d "Write a short story about a cat."

Example output:

data: {"text":"Once "}
curl -sSfX POST http://localhost:9090/v1/conversations/resume-check \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $(get-token)" \
  -d '["7aa65d1d-ec04-46d7-b0cc-6bf6f96ca4b7"]'

Example output:

[]

Resume the interrupted response:

curl -NsSfX GET http://localhost:9090/v1/conversations/7aa65d1d-ec04-46d7-b0cc-6bf6f96ca4b7/resume \
  --max-time 0.5 \
  -H "Authorization: Bearer $(get-token)"

Example output:

data: {"text":"Once "}