Files · Return reason agent for Shopify merchants
74 (1 binary, 679.5 kB total)attempt 1
README.md·5426 B·markdown
markdown
# Return reason agent for Shopify merchants
> Automatically classify return reasons from Shopify customers and trigger refund, replacement, or store-credit decisions without human review. Uses a provider-agnostic LLM (OpenAI-compatible), the A2A protocol for agent-to-agent communication, intent classification via `@reaatech/agent-mesh-classifier`, and per-merchant budget enforcement via `@reaatech/agent-budget-engine`.
## Prerequisites
- Node.js >=22, pnpm 10
- Shopify Partner account with a development store and API credentials (API key, secret, offline access token)
- An OpenAI-compatible LLM provider key (OpenAI, DeepSeek, Groq, etc.)
- (Optional) Langfuse account for LLM observability
## Quick start
1. `pnpm install`
2. Copy `.env.example` to `.env` and fill in every variable
3. Start the Fastify A2A server: `npx tsx src/server.ts`
4. In another terminal, start the Next.js dev server: `pnpm dev`
5. Test the classification endpoint:
```
curl -X POST http://localhost:3000/api/classify \
-H "Content-Type: application/json" \
-d '{"orderId":"ord-1","productId":"prod-1","reasonText":"the item arrived broken"}'
```
## Architecture
- **Next.js App Router** — provides the dashboard page and API routes (`/api/classify`, `/api/health`)
- **Fastify A2A server** — runs alongside Next.js, exposes A2A protocol endpoints via a Hono adapter (`createA2AHonoApp`)
- **`@reaatech/a2a-reference-client`** — A2A client SDK for task submission, agent discovery, and SSE streaming
- **`@reaatech/a2a-reference-server`** — A2A server framework with rate limiting, health checks, and JSON-RPC 2.0 endpoints
- **`@reaatech/agent-mesh-classifier`** — Gemini Flash intent classifier that maps return reasons to agent actions (refund/replace/store-credit/escalate)
- **`@reaatech/agent-budget-engine`** — Per-merchant budget enforcement with pre-flight checks, real-time spend recording, and threshold-based state transitions
- **`@reaatech/llm-router-core`** — Core routing types for model definitions and cost telemetry
- **`@reaatech/agent-mesh`** — Domain types for protocol messages, context packets, and classifier outputs
- **`openai`** — Provider-agnostic LLM client (configurable base URL for any OpenAI-compatible API)
- **`@shopify/shopify-api`** — Shopify Admin API client for order retrieval, refund creation, and order notes
- **`langfuse`** — Optional LLM observability (traces, spans, token tracking)
## Environment variables
| Variable | Description | Default | Required |
|---|---|---|---|
| `LLM_API_KEY` | OpenAI-compatible LLM provider API key | — | Yes |
| `LLM_BASE_URL` | Base URL for the LLM API | `https://api.openai.com` | No |
| `LLM_MODEL` | Model identifier to use | `gpt-5.2` | No |
| `SHOPIFY_API_KEY` | Shopify API client key | — | Yes |
| `SHOPIFY_API_SECRET` | Shopify API client secret | — | Yes |
| `SHOPIFY_SHOP_DOMAIN` | Shopify store domain (e.g. `my-store.myshopify.com`) | — | Yes |
| `SHOPIFY_ACCESS_TOKEN` | Shopify Admin API offline access token | — | Yes |
| `BUDGET_LIMIT_USD` | Per-merchant daily budget in USD | `5` | No |
| `BUDGET_SOFT_CAP` | Budget soft cap as fraction (0.0–1.0) | `0.8` | No |
| `LANGFUSE_PUBLIC_KEY` | Langfuse project public key | — | No |
| `LANGFUSE_SECRET_KEY` | Langfuse project secret key | — | No |
| `LANGFUSE_HOST` | Langfuse self-hosted base URL | `https://cloud.langfuse.com` | No |
| `A2A_SERVER_PORT` | Port for the Fastify A2A server | `3001` | No |
| `A2A_SERVER_BASE_URL` | A2A server base URL | `http://localhost:3001` | No |
## Project structure
```
.
├── app/
│ ├── api/
│ │ ├── classify/route.ts # POST — classify a return reason
│ │ └── health/route.ts # GET — health check
│ └── page.tsx # Minimal dashboard form
├── src/
│ ├── lib/
│ │ ├── config.ts # Zod-validated environment config
│ │ ├── llm-client.ts # OpenAI SDK wrapper (provider-agnostic)
│ │ ├── observability.ts # Langfuse tracing helpers
│ │ └── types.ts # Domain types, schemas, and REAA re-exports
│ ├── services/
│ │ ├── a2a-client-service.ts # A2AClient factory and helpers
│ │ ├── a2a-server-service.ts # A2A Hono app with agent executor
│ │ ├── budget-service.ts # BudgetController + InMemorySpendStore
│ │ ├── classifier-service.ts # agent-mesh-classifier wrapper
│ │ ├── return-reason-agent.ts # Main orchestrator
│ │ └── shopify-client.ts # Shopify API client
│ └── server.ts # Fastify entry point (A2A + webhooks)
├── tests/
│ ├── setup.ts # MSW handlers + env vars
│ ├── helpers.ts # Test data factories
│ ├── api-routes.test.ts
│ ├── budget-service.test.ts
│ ├── classifier-service.test.ts
│ ├── llm-client.test.ts
│ ├── return-reason-agent.test.ts
│ ├── shopify-client.test.ts
│ └── types.test.ts
├── .env.example
├── package.json
└── README.md
```
## Testing
- Run tests: `pnpm test`
- All external HTTP calls are mocked via MSW — no real API keys needed
- Coverage reports in `./coverage/`
## License
MIT