{"slug": "the-5-pieces-of-ai-plumbing-every-saas-needs-in-2026-with-code", "title": "The 5 pieces of AI plumbing every SaaS needs in 2026 (with code)", "summary": "A developer has open-sourced five essential AI plumbing components for SaaS applications in 2026, providing working TypeScript code for Next.js 15. The components include streaming tokens via server-sent events, typed tool execution with Zod, usage metering to control API costs, prompt caching optimization, and robust SSE buffer parsing. The code is available in the MIT-licensed agentship-lite repository, with a full SaaS version called AgentShip offered as early access for £49.", "body_md": "Every SaaS is adding AI features in 2026. Most teams burn the first two weeks on the same five pieces of plumbing — none of which are the actual product. Here's each one, with working TypeScript for Next.js 15.\n\nUsers won't stare at a spinner for 20 seconds. Stream tokens as they generate with server-sent events:\n\n``` js\n// app/api/chat/route.ts\nconst runner = anthropic.beta.messages.toolRunner({\n  model: \"claude-opus-4-8\",\n  max_tokens: 64000,\n  thinking: { type: \"adaptive\" },\n  system: SYSTEM_PROMPT,\n  tools,\n  messages,\n  stream: true,\n});\n\nconst stream = new ReadableStream({\n  async start(controller) {\n    for await (const messageStream of runner) {\n      for await (const event of messageStream) {\n        if (event.type === \"content_block_delta\" && event.delta.type === \"text_delta\") {\n          controller.enqueue(encode(`data: ${JSON.stringify({ text: event.delta.text })}\\n\\n`));\n        }\n      }\n    }\n    controller.close();\n  },\n});\nreturn new Response(stream, { headers: { \"Content-Type\": \"text/event-stream\" } });\n```\n\nThe difference between a chatbot and a product is tools — the model acting on *your* data. Define them once with Zod; the SDK's tool runner handles the execution loop:\n\n``` js\nexport const searchOrders = betaZodTool({\n  name: \"search_orders\",\n  description: \"Look up a customer's orders. Call when the user asks about order status.\",\n  inputSchema: z.object({ email: z.string().email() }),\n  run: async ({ email }) => db.orders.findByEmail(email),\n});\n```\n\nNo manual agentic loop, no JSON schema by hand, inputs typed end to end.\n\nOne enthusiastic user on your £10/month plan can generate £200 of API costs. Meter every request and weight output tokens (they cost ~5x input):\n\n```\nexport function billableUnits(u: Usage): number {\n  return u.input_tokens + (u.cache_read_input_tokens ?? 0) / 10 + u.output_tokens * 5;\n}\n// After each response:\nawait recordUsage(userId, billableUnits(message.usage));\n// Before each request:\nif (await getUsage(userId) > planLimit) return quotaExceeded();\n```\n\nPrompt caching can cut input costs ~90% — but it's a *prefix match*. One interpolated timestamp in your system prompt and you pay full price on every request. Rules:\n\n``` js\nexport const SYSTEM_PROMPT = [{\n  type: \"text\" as const,\n  text: STABLE_INSTRUCTIONS,          // never interpolate into this\n  cache_control: { type: \"ephemeral\" as const },\n}];\n```\n\nVerify it works: `usage.cache_read_input_tokens`\n\nshould be non-zero from the second request on.\n\nParse the SSE buffer across chunk boundaries — the naive `split`\n\non every chunk drops tokens:\n\n``` js\nlet buffer = \"\";\nwhile (true) {\n  const { done, value } = await reader.read();\n  if (done) break;\n  buffer += decoder.decode(value, { stream: true });\n  const lines = buffer.split(\"\\n\\n\");\n  buffer = lines.pop() ?? \"\";   // keep the partial event for the next chunk\n  for (const line of lines) handleEvent(line);\n}\n```\n\nAll five pieces above are open source (MIT) in [agentship-lite](https://github.com/mt211211/agentship-lite) — copy them into any Next.js app.\n\nIf you want the full SaaS around it — Stripe subscriptions, auth, Postgres schema, plan gating wired to the metering — that's [AgentShip](https://mt211211.github.io/agentship-site/), currently £49 early access.", "url": "https://wpnews.pro/news/the-5-pieces-of-ai-plumbing-every-saas-needs-in-2026-with-code", "canonical_source": "https://dev.to/mt211211/the-5-pieces-of-ai-plumbing-every-saas-needs-in-2026-with-code-1270", "published_at": "2026-06-12 20:49:51+00:00", "updated_at": "2026-06-12 21:14:21.498664+00:00", "lang": "en", "topics": ["ai-infrastructure", "ai-tools", "ai-products", "ai-startups", "mlops"], "entities": ["Anthropic", "Claude", "Next.js", "Zod", "AgentShip", "agentship-lite", "Stripe", "Postgres"], "alternates": {"html": "https://wpnews.pro/news/the-5-pieces-of-ai-plumbing-every-saas-needs-in-2026-with-code", "markdown": "https://wpnews.pro/news/the-5-pieces-of-ai-plumbing-every-saas-needs-in-2026-with-code.md", "text": "https://wpnews.pro/news/the-5-pieces-of-ai-plumbing-every-saas-needs-in-2026-with-code.txt", "jsonld": "https://wpnews.pro/news/the-5-pieces-of-ai-plumbing-every-saas-needs-in-2026-with-code.jsonld"}}