Skip to content

Commit 4a113f8

Browse files
Merge branch 'Gerome-Elassaad:main' into main
2 parents fa256c8 + f0149cc commit 4a113f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+4393
-7368
lines changed

.gitignore

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,18 @@
1010
/coverage
1111

1212
# demo files (temporary for testing)
13-
/app/demo
14-
/components/demo-enhanced-interpreter.tsx
1513
.env.local
1614

1715
# next.js
1816
/.next/
1917
/out/
2018

21-
.claude
22-
23-
claude.md
24-
2519
.env
2620

2721
.mcp.json
2822

23+
.temp
24+
2925
# production
3026
/build
3127

@@ -49,13 +45,12 @@ yarn-error.log*
4945
*.tsbuildinfo
5046
next-env.d.ts
5147

52-
gcp.json
53-
.vercel
54-
55-
supabase
5648

5749
.env
58-
schemas
50+
5951
scripts
6052
.vscode
61-
mcp.json
53+
mcp.json
54+
55+
CLAUDE.md
56+
.claude

LLM.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,4 @@ RULES
259259
- Explain technical decisions in terms users can understand
260260
- Your goal is to empower users to build amazing applications quickly and efficiently
261261

262-
Your primary objective is to help users create functional, professional-grade applications that work immediately and can be easily customized and extended.
262+
Your primary objective is to help users create functional, professional-grade applications that work immediately and can be easily customized and extended.

app/api/chat/morph-chat/route.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { handleAPIError, createRateLimitResponse } from '@/lib/api-errors'
2+
import { Duration } from '@/lib/duration'
3+
import { getModelClient, LLMModel, LLMModelConfig } from '@/lib/models'
4+
import { applyPatch } from '@/lib/morph'
5+
import ratelimit from '@/lib/ratelimit'
6+
import { FragmentSchema, morphEditSchema, MorphEditSchema } from '@/lib/schema'
7+
import { generateObject, LanguageModel, CoreMessage } from 'ai'
8+
9+
export const maxDuration = 300
10+
11+
const rateLimitMaxRequests = process.env.RATE_LIMIT_MAX_REQUESTS
12+
? parseInt(process.env.RATE_LIMIT_MAX_REQUESTS)
13+
: 10
14+
const ratelimitWindow = process.env.RATE_LIMIT_WINDOW
15+
? (process.env.RATE_LIMIT_WINDOW as Duration)
16+
: '1d'
17+
18+
19+
export async function POST(req: Request) {
20+
const {
21+
messages,
22+
model,
23+
config,
24+
currentFragment,
25+
}: {
26+
messages: CoreMessage[]
27+
model: LLMModel
28+
config: LLMModelConfig
29+
currentFragment: FragmentSchema
30+
} = await req.json()
31+
32+
// Rate limiting (same as chat route)
33+
const limit = !config.apiKey
34+
? await ratelimit(
35+
req.headers.get('x-forwarded-for'),
36+
rateLimitMaxRequests,
37+
ratelimitWindow,
38+
)
39+
: false
40+
41+
if (limit) {
42+
return createRateLimitResponse(limit)
43+
}
44+
45+
const { model: _model, apiKey: _apiKey, ...modelParams } = config
46+
const modelClient = getModelClient(model, config)
47+
48+
try {
49+
const contextualSystemPrompt = `You are a code editor. Generate a JSON response with exactly these fields:
50+
51+
{
52+
"commentary": "Explain what changes you are making",
53+
"instruction": "One line description of the change",
54+
"edit": "The code changes with // ... existing code ... for unchanged parts",
55+
"file_path": "${currentFragment.file_path}"
56+
}
57+
58+
Current file: ${currentFragment.file_path}
59+
Current code:
60+
\`\`\`
61+
${currentFragment.code}
62+
\`\`\`
63+
64+
`
65+
66+
const result = await generateObject({
67+
model: modelClient as LanguageModel,
68+
system: contextualSystemPrompt,
69+
messages,
70+
schema: morphEditSchema,
71+
maxRetries: 0,
72+
...modelParams,
73+
})
74+
75+
const editInstructions = result.object
76+
77+
// Apply edits using Morph
78+
const morphResult = await applyPatch({
79+
targetFile: currentFragment.file_path,
80+
instructions: editInstructions.instruction,
81+
initialCode: currentFragment.code,
82+
codeEdit: editInstructions.edit,
83+
})
84+
85+
// Return updated fragment in standard format
86+
const updatedFragment: FragmentSchema = {
87+
...currentFragment,
88+
code: morphResult.code,
89+
commentary: editInstructions.commentary,
90+
}
91+
92+
// Create a streaming response that matches the AI SDK format
93+
const encoder = new TextEncoder()
94+
const stream = new ReadableStream({
95+
start(controller) {
96+
const json = JSON.stringify(updatedFragment)
97+
controller.enqueue(encoder.encode(json))
98+
controller.close()
99+
},
100+
})
101+
102+
return new Response(stream, {
103+
headers: {
104+
'Content-Type': 'text/plain; charset=utf-8',
105+
},
106+
})
107+
} catch (error: any) {
108+
return handleAPIError(error, { hasOwnApiKey: !!config.apiKey })
109+
}
110+
}

app/api/chat/route.ts

Lines changed: 8 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
1+
import { handleAPIError, createRateLimitResponse } from '@/lib/api-errors'
12
import { Duration } from '@/lib/duration'
2-
import {
3-
getModelClient,
4-
LLMModel,
5-
LLMModelConfig,
6-
} from '@/lib/models'
3+
import { getModelClient, LLMModel, LLMModelConfig } from '@/lib/models'
74
import { toPrompt } from '@/lib/prompt'
85
import ratelimit from '@/lib/ratelimit'
96
import { fragmentSchema as schema } from '@/lib/schema'
107
import { Templates } from '@/lib/templates'
118
import { streamObject, LanguageModel, CoreMessage } from 'ai'
129

1310
export const maxDuration = 300
14-
export const runtime = 'nodejs'
15-
export const dynamic = 'force-dynamic'
1611

1712
const rateLimitMaxRequests = process.env.RATE_LIMIT_MAX_REQUESTS
1813
? parseInt(process.env.RATE_LIMIT_MAX_REQUESTS)
@@ -47,21 +42,14 @@ export async function POST(req: Request) {
4742
: false
4843

4944
if (limit) {
50-
return new Response('You have reached your request limit for the day.', {
51-
status: 429,
52-
headers: {
53-
'X-RateLimit-Limit': limit.amount.toString(),
54-
'X-RateLimit-Remaining': limit.remaining.toString(),
55-
'X-RateLimit-Reset': limit.reset.toString(),
56-
},
57-
})
45+
return createRateLimitResponse(limit)
5846
}
5947

6048
console.log('userID', userID)
6149
console.log('teamID', teamID)
62-
console.log('template', template)
50+
// console.log('template', template)
6351
console.log('model', model)
64-
console.log('config', config)
52+
// console.log('config', config)
6553

6654
const { model: modelNameString, apiKey: modelApiKey, ...modelParams } = config
6755
const modelClient = getModelClient(model, config)
@@ -72,53 +60,12 @@ export async function POST(req: Request) {
7260
schema,
7361
system: toPrompt(template),
7462
messages,
75-
maxRetries: 2,
63+
maxRetries: 0, // do not retry on errors
7664
...modelParams,
7765
})
7866

7967
return stream.toTextStreamResponse()
8068
} catch (error: any) {
81-
const isRateLimitError =
82-
error && (error.statusCode === 429 || error.message.includes('limit'))
83-
const isOverloadedError =
84-
error && (error.statusCode === 529 || error.statusCode === 503)
85-
const isAccessDeniedError =
86-
error && (error.statusCode === 403 || error.statusCode === 401)
87-
88-
if (isRateLimitError) {
89-
return new Response(
90-
'The provider is currently unavailable due to request limit. Try using your own API key.',
91-
{
92-
status: 429,
93-
},
94-
)
95-
}
96-
97-
if (isOverloadedError) {
98-
return new Response(
99-
'The provider is currently unavailable. Please try again later.',
100-
{
101-
status: 529,
102-
},
103-
)
104-
}
105-
106-
if (isAccessDeniedError) {
107-
return new Response(
108-
'Access denied. Please make sure your API key is valid.',
109-
{
110-
status: 403,
111-
},
112-
)
113-
}
114-
115-
console.error('Error:', error)
116-
117-
return new Response(
118-
'An unexpected error has occurred. Please try again later.',
119-
{
120-
status: 500,
121-
},
122-
)
69+
return handleAPIError(error, { hasOwnApiKey: !!config.apiKey })
12370
}
124-
}
71+
}

app/api/subscription/usage/route.ts

Lines changed: 0 additions & 60 deletions
This file was deleted.

0 commit comments

Comments
 (0)