Skip to content
reaatech

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