Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
da3ff55
test: add unit tests for ClaudeAgentSDKRepository
Diplow Nov 1, 2025
315c1b5
feat: implement ClaudeAgentSDKRepository
Diplow Nov 1, 2025
d66133e
refactor: fix quality violations in ClaudeAgentSDKRepository
Diplow Nov 1, 2025
5086e93
docs: update README for ClaudeAgentSDKRepository
Diplow Nov 1, 2025
4d9fcb5
test: add unit tests for AgenticService tools and subagent functionality
Diplow Nov 1, 2025
dc2e2a1
feat: add tools parameter and subagent management to AgenticService
Diplow Nov 1, 2025
11b3e94
refactor: fix rule of 6 violation - group LLM config parameters
Diplow Nov 1, 2025
e22a0ff
docs: update services README for tools and subagent features
Diplow Nov 1, 2025
236f4d8
fix: resolve unsafe assignment lint error in service tests
Diplow Nov 1, 2025
dbc8a49
test: add unit tests for SDK-specific type definitions
Diplow Nov 1, 2025
8b0afc8
feat: implement SDK-specific type definitions
Diplow Nov 1, 2025
977d2f7
docs: add README for agentic types subsystem
Diplow Nov 1, 2025
a50a681
test: add unit tests for Inngest SDK async generator compatibility
Diplow Nov 1, 2025
19f6627
feat: update Inngest infrastructure for SDK async generator compatibi…
Diplow Nov 1, 2025
eed09c1
docs: add README for Inngest SDK compatibility infrastructure
Diplow Nov 1, 2025
4c32216
refactor: fix quality violations in Claude Agent SDK integration
Diplow Nov 1, 2025
a2ba4c2
test: add unit tests for generateResponse endpoint with MCP tools int…
Diplow Nov 1, 2025
5c5a8b0
feat: implement generateResponse endpoint with MCP tools integration
Diplow Nov 1, 2025
51f4fae
docs: update README for generateResponse endpoint with MCP tools inte…
Diplow Nov 1, 2025
604dfe6
test: add unit tests for MCP tools
Diplow Nov 1, 2025
37d3e2c
feat: implement createMCPTools with mapping and IAM service wrappers
Diplow Nov 1, 2025
7f8500d
refactor: fix quality violations in MCP tools
Diplow Nov 1, 2025
8f21ccc
docs: update README for MCP tools
Diplow Nov 1, 2025
6d43163
refactor: expose MCP tools through map router public API
Diplow Nov 2, 2025
e13952c
docs: update server README for MCP tools and SDK integration
Diplow Nov 2, 2025
3503a05
fix: enable Claude Agent SDK by default with preferClaudeSDK flag
Diplow Nov 2, 2025
7c274a9
fix: set Claude Sonnet 4 as default model and disable queue for testing
Diplow Nov 2, 2025
984c0e0
feat: add Claude Haiku 4.5 and set as default model for debugging
Diplow Nov 2, 2025
4c8e41a
fix: update to actual Claude model IDs from Anthropic API
Diplow Nov 2, 2025
0daca06
debug: add detailed error logging to Claude SDK repository
Diplow Nov 2, 2025
e99cb0b
fix: pass ANTHROPIC_API_KEY to Claude Code subprocess via env option
Diplow Nov 2, 2025
b2cec57
fix: resolve Claude Agent SDK integration issues
Diplow Nov 2, 2025
72df31e
feat: integrate Claude Agent SDK with HTTP MCP server for authenticat…
Diplow Nov 2, 2025
0be3ae5
feat: optimize internal API key validation with userId hint
Diplow Nov 2, 2025
c0212d0
fix: resolve all architecture violations
Diplow Nov 2, 2025
1f9a729
feat: add hierarchical AI context with composed tiles support
Diplow Nov 2, 2025
d084d60
feat: optimize AI context fetching with multi-query field selection
Diplow Nov 2, 2025
f0cd0a7
fix: resolve all architecture violations
Diplow Nov 2, 2025
52b5256
refactor: decouple agentic domain from mapping by moving context type…
Diplow Nov 2, 2025
81c93f2
refactor: remove redundant MCP tools and fix backend->frontend depend…
Diplow Nov 3, 2025
970fed4
Merge pull request #151 from Diplow/feature-claude-sdk
Diplow Nov 3, 2025
79db2a3
refactor: remove unused tools parameter and add DB constraint
Diplow Nov 3, 2025
7c50fac
feat: add Vercel Sandbox integration for Claude Agent SDK
Diplow Nov 3, 2025
a45851d
refactor: enhance error logging in AuthProvider to use useEffect for …
Diplow Nov 3, 2025
6483dc4
fix: resolve ESLint issues
Diplow Nov 3, 2025
ec7a93b
refactor: remove verbose debug logging from Anthropic proxy and SDK i…
Diplow Nov 4, 2025
bca8391
docs: add comprehensive Claude SDK security architecture documentation
Diplow Nov 4, 2025
9eba7a5
feat: implement short-lived MCP session tokens (10 min TTL)
Diplow Nov 5, 2025
f261f9f
feat: add input validation to internal API key service functions
Diplow Nov 5, 2025
ee20df8
refactor: extract duplicated canvas strategy mapping to helper function
Diplow Nov 5, 2025
aca80c1
security: harden network interceptor and proxy configuration
Diplow Nov 5, 2025
05c53f2
fix: correct parent path calculation and composition filtering in map…
Diplow Nov 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions .env.production.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,45 @@ BETTER_AUTH_URL=
# MISTRAL_API_KEY=
# YOUTUBE_API_KEY=

# OpenRouter API Key (REQUIRED for AI chat features)
# === LLM PROVIDER CONFIGURATION ===

# LLM Provider Selection (optional, defaults to "openrouter")
# Options: "openrouter" or "claude-agent-sdk"
#
# - "openrouter": Multi-model proxy service with pay-per-use pricing
# Compatible with OpenAI, Anthropic, Google, Meta, and more
# Recommended for production due to flexibility and cost control
#
# - "claude-agent-sdk": Direct Anthropic Claude Agent SDK integration
# Requires ANTHROPIC_API_KEY, uses async generators for streaming
# Provides access to advanced agent capabilities and tool use
#
LLM_PROVIDER=openrouter

# OpenRouter API Key (REQUIRED if LLM_PROVIDER=openrouter)
# Get yours at: https://openrouter.ai/keys
# IMPORTANT: Set spending limits in OpenRouter dashboard for safety!
OPENROUTER_API_KEY=sk-or-v1-...

# Anthropic API Key (REQUIRED if LLM_PROVIDER=claude-agent-sdk)
# Get yours at: https://console.anthropic.com/
# Provides direct access to Claude models via the Agent SDK
ANTHROPIC_API_KEY=sk-ant-...

# === VERCEL SANDBOX CONFIGURATION (for Claude Agent SDK in production) ===

# Enable Vercel Sandbox for isolated code execution
# IMPORTANT: Set to "true" when using claude-agent-sdk in production on Vercel
# The Claude Agent SDK spawns subprocesses which don't work in standard serverless
# Vercel Sandbox provides isolated microVMs for safe AI agent execution
USE_SANDBOX=true

# Vercel OIDC Token (REQUIRED if USE_SANDBOX=true)
# In production: Automatically provided by Vercel as VERCEL_OIDC_TOKEN
# In development: Run `vercel env pull .env.local` to get development token
# This is NOT the same as a personal access token from vercel.com/account/tokens
VERCEL_OIDC_TOKEN=

# Email Configuration (REQUIRED for email verification in production)
# Brevo (formerly Sendinblue) - Recommended for Hexframe
# Get your API key at: https://app.brevo.com/settings/keys/api
Expand Down Expand Up @@ -54,4 +88,4 @@ USE_QUEUE=true

# Monitoring (optional)
# SENTRY_DSN=
# VERCEL_ANALYTICS_ID=
# VERCEL_ANALYTICS_ID=
164 changes: 164 additions & 0 deletions docs/ANTHROPIC_PROXY_SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# Anthropic API Proxy Security

## Problem

When running Claude Agent SDK in Vercel Sandbox, the `ANTHROPIC_API_KEY` must be provided as an environment variable. This creates a security risk: malicious users could extract the API key from the sandbox environment.

## Solution: Secure Proxy

Instead of exposing the API key directly, we route all Anthropic API calls through a secure proxy endpoint.

### Architecture

```
┌─────────────────────────────────────────────┐
│ Vercel Sandbox (Untrusted) │
│ │
│ Claude Agent SDK │
│ ├─ ANTHROPIC_BASE_URL = /api/anthropic... │
│ └─ ANTHROPIC_API_KEY = "placeholder" │
│ │
│ [No real API key exposed] │
└──────────────┬──────────────────────────────┘
│ Authenticated requests
│ (user_id + secret in URL)
┌─────────────────────────────────────────────┐
│ /api/anthropic-proxy (Trusted) │
│ │
│ 1. Verify internal auth secret │
│ 2. Check rate limits per user │
│ 3. Add real ANTHROPIC_API_KEY │
│ 4. Forward to api.anthropic.com │
│ 5. Return response │
└─────────────────────────────────────────────┘
```
Comment on lines +13 to +35
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix Markdown fenced block language.

markdownlint is failing (MD040) because the architecture block lacks a language hint. Please declare it (e.g. text) so docs builds stay green.

-```
+```text-```
+```
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

13-13: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In docs/ANTHROPIC_PROXY_SECURITY.md around lines 13 to 35 the fenced code block
used to render the ASCII architecture diagram lacks a language hint which
triggers markdownlint MD040; update the opening fence to include a language tag
(e.g., change ``` to ```text) so the block is explicitly marked as text and
linting/doc builds pass.


## Implementation

### 1. Proxy Endpoint

**File:** `src/app/api/anthropic-proxy/route.ts`

- Accepts requests with `user_id` and `auth` query parameters
- Validates internal authentication secret
- Enforces per-user rate limiting (50 requests/hour by default)
- Adds the real `ANTHROPIC_API_KEY` before forwarding to Anthropic
- Supports streaming and non-streaming requests

### 2. Sandbox Configuration

**File:** `src/lib/domains/agentic/repositories/claude-agent-sdk-sandbox.repository.ts`

```typescript
// Set proxy URL with authentication
const proxyUrl = `${baseUrl}/api/anthropic-proxy?user_id=${userId}&auth=${secret}`
process.env.ANTHROPIC_BASE_URL = proxyUrl

// Placeholder key (never used)
process.env.ANTHROPIC_API_KEY = 'placeholder-key-not-used'
```

## Security Features

### 1. Internal Authentication
- Requests must include `INTERNAL_PROXY_SECRET`
- Secret is never exposed to sandbox (only in query string generated server-side)
- Generate a strong random secret for production

### 2. Rate Limiting
- 50 requests/hour per user (configurable)
- Prevents abuse even if authentication is compromised
- In-memory tracking (use Redis for production)

### 3. Budget Limits
- `maxBudgetUsd: 1.0` per SDK request
- Additional limit at SDK level
- Prevents runaway costs

### 4. Request Validation
- Body validation before forwarding
- Suspicious pattern detection (optional)
- Request logging for monitoring

## Environment Variables

```bash
# Required
ANTHROPIC_API_KEY=sk-ant-... # Real API key (server-side only)
INTERNAL_PROXY_SECRET=<random> # Generate with: openssl rand -hex 32

# Optional
HEXFRAME_API_BASE_URL=https://... # Your app URL for proxy
```

## Production Setup

1. **Generate secure secret:**
```bash
openssl rand -hex 32
```

2. **Add to Vercel:**
- Go to Project Settings → Environment Variables
- Add `INTERNAL_PROXY_SECRET` with the generated value
- Scope: Production, Preview, Development

3. **Verify:**
- `ANTHROPIC_API_KEY` is set (for proxy to use)
- `INTERNAL_PROXY_SECRET` is set (for auth)
- `HEXFRAME_API_BASE_URL` points to your domain

## Monitoring

Monitor for:
- Rate limit violations (potential abuse)
- Failed auth attempts
- Unusual API usage patterns
- High costs per user

Check logs:
```typescript
loggers.agentic('Anthropic proxy: ...', { userId, ... })
```

## Limitations

### What This Protects Against
✅ Direct API key extraction from process.env
✅ Unlimited API usage per user
✅ Untracked API consumption

### What This Doesn't Protect Against
⚠️ Sophisticated attacks (sandbox escape, timing attacks)
⚠️ Auth secret extraction (if sandbox can read its own request URLs)
⚠️ Replay attacks (no nonce/timestamp validation)

### Additional Hardening (Optional)

For maximum security:
1. **Use time-based tokens:** Include timestamp in auth, reject old requests
2. **Use per-request nonces:** Prevent replay attacks
3. **Use Redis for rate limiting:** More robust than in-memory
4. **Monitor sandbox logs:** Detect key extraction attempts
5. **Rotate secrets regularly:** Weekly/monthly rotation

## Cost Control

Even with leaked credentials, damage is limited by:
- **Rate limiting:** 50 req/hour = max ~$1-2/hour (at $0.02/req avg)
- **Budget limits:** $1.00 max per SDK request
- **Monitoring:** Alerts on unusual usage

## Alternative: Don't Use Sandbox

If security concerns are too high:
- Set `LLM_PROVIDER=openrouter` in production
- Keep Claude SDK for development only
- Simpler but loses agent capabilities

## References

- [Anthropic SDK Base URL](https://github.com/anthropics/anthropic-sdk-typescript)
- [Vercel Sandbox Docs](https://vercel.com/docs/vercel-sandbox)
- [Implementation PR](#) <!-- Add PR link when merged -->
Comment on lines +162 to +164
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Replace the placeholder PR link.

markdownlint (MD042) rejects the empty (#) link. Point it at the actual PR URL so the doc and lint both succeed.

-- [Implementation PR](#) <!-- Add PR link when merged -->
+- [Implementation PR](https://github.com/Diplow/hexframe/pull/152)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- [Anthropic SDK Base URL](https://github.com/anthropics/anthropic-sdk-typescript)
- [Vercel Sandbox Docs](https://vercel.com/docs/vercel-sandbox)
- [Implementation PR](#) <!-- Add PR link when merged -->
- [Anthropic SDK Base URL](https://github.com/anthropics/anthropic-sdk-typescript)
- [Vercel Sandbox Docs](https://vercel.com/docs/vercel-sandbox)
- [Implementation PR](https://github.com/Diplow/hexframe/pull/152)
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

164-164: No empty links

(MD042, no-empty-links)

🤖 Prompt for AI Agents
In docs/ANTHROPIC_PROXY_SECURITY.md around lines 162 to 164, the Implementation
PR link is a placeholder "(#)" which triggers markdownlint MD042; replace that
placeholder with the actual pull request URL (absolute or repo-relative, e.g.
https://github.com/ORG/REPO/pull/NNN or ../pull/NNN) so the link is non-empty,
or if the PR URL is not yet available remove the link entirely and add a TODO
comment instead; ensure the final markdown uses a valid non-empty link target to
satisfy the linter.

Loading
Loading