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-serviceCLI 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:
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:
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 "}