What it is : A reference implementation of a multi-agent enterprise assistant. One orchestrator routes requests, three specialist workers handle retrieval, SQL, and structured output generation. The data layer uses Postgres with Row-Level Security policies keyed to the authenticated session, so agents cannot read rows the user cannot read, regardless of how they are prompted. Deployed as a Next.js app on Fly.io with a live demo.
Why I built it : Most public multi-agent demos skip the parts that matter in production: identity, data boundaries, cost, and failure handling. This repo exists as a working counter-example. Scope is deliberately small so the structure stays readable: one orchestrator prompt, three worker prompts, one RLS policy, one tracing hook.
Architecture :
[Hero diagram placeholder: orchestrator at top, three workers below, Postgres with RLS below, trust boundaries labelled between the agent plane and the data plane.]
The orchestrator receives the user request plus a scoped session token. It picks workers based on a short routing prompt. Workers are stateless and receive only the subset of session context they need. Every Postgres query runs under the user's RLS session, not a service account. A prompt-injection attack cannot escalate what rows are visible, because escalation would require database-level identity, not just a convincing prompt.
Threat model :
- Prevented: cross-tenant data read via prompt injection. RLS enforces identity at the database, independent of agent reasoning.
- Prevented: credential or token leak via tool arguments. Tool inputs pass a payload classifier before dispatch.
- Not prevented: prompt injection that causes the orchestrator to decline a legitimate request. Availability, not confidentiality.
- Not prevented: cost exhaustion by a user within their own data scope. Rate limits mitigate but do not eliminate.
- Partially prevented: schema inference via error timing. Error strings are sanitized, but timing probes remain feasible.
Prompt caching :
System prompts and tool catalogs sit above the user turn boundary so repeat sessions reuse them. Caching code lives in lib/cache.ts. Measured hit rate on the demo workload: [TODO: measured number]. Dollar cost delta vs no-cache: [TODO: measured number].
Live demo : Each visitor gets a scoped session seeded with sample tenant data. A reset button clears session state. Daily per-IP cap in place to keep costs bounded. Repo and live URL: github.com/JayDS22/enterprise-assistant-reference.
What this does not do :
- Not a framework. Copy the pieces you need; do not depend on it.
- No full OAuth implementation. Session tokens are stubbed for demo purposes.
- No fine-tuning. Behavior is driven by prompting, tool design, and the RLS policy.
- Does not solve agent reliability. Expect 85 to 95 percent task completion on the demo task suite, not 100 percent.
What's next :
- Claude Agent SDK variant in a sibling directory, same scenario, side-by-side comparison.
- Prompt-caching hit rate and cost deltas published with real numbers.
- Red-team gallery: five specific prompts that break the system, root cause per failure.
Tech stack :
Runtime: TypeScript, Next.js (App Router), Node.js
Agents: OpenAI Agents SDK, Responses API, tool use with JSON schema validation
Data: Postgres with Row-Level Security, Drizzle ORM
Deploy: Fly.io (app), Fly Postgres (data), GitHub Actions (CI)
Observability: Structured JSON logs, request IDs correlated across orchestrator and workers