kalhdrawi commited on
Commit
c586a80
·
1 Parent(s): e3c1646

Reupload OmniDev clean version

Browse files
app/api/augment/route.ts CHANGED
@@ -6,26 +6,26 @@ import { InferenceClient } from "@huggingface/inference";
6
  import type { AugmentRequest, AugmentResponse } from "@/types";
7
 
8
  const SYS = `You are Omni Engine, an autonomous code evolution system.
9
- You receive:
10
- - project context (tree + critical file excerpts)
11
  - a user instruction
12
 
13
- You MUST respond ONLY with strict JSON, no comments, no markdown fences.
14
- JSON schema:
 
15
  {
16
  "ok": true,
17
  "summary": string,
18
  "logs": string[],
19
- "files": [
20
- { "path": string, "action": "add"|"update"|"delete", "content"?: string, "note"?: string }
21
- ]
22
  }
 
23
 
24
- Constraints:
25
- - Ensure paths are POSIX-like and rooted from repo (e.g., /frontend/src/App.tsx)
26
- - For add/update, provide full file content (ready to run)
27
- - Keep changes minimal and consistent
28
- - Produce compilable code for the chosen language/framework
29
  `;
30
 
31
  function cleanText(raw: string): string {
@@ -66,6 +66,46 @@ function tryParseAny(jsonish: string): any {
66
  }
67
  }
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  export async function POST(req: NextRequest) {
70
  try {
71
  const body = (await req.json()) as AugmentRequest;
@@ -123,10 +163,29 @@ export async function POST(req: NextRequest) {
123
  }
124
 
125
  let json: any;
 
126
  try {
127
  json = tryParseAny(cleaned);
128
  } catch (e: any) {
129
- return NextResponse.json({ ok: false, message: e?.message || "Invalid JSON from model", raw: text } as any, { status: 500 });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  }
131
 
132
  // Minimal validation
@@ -137,6 +196,23 @@ export async function POST(req: NextRequest) {
137
  if (Array.isArray(json)) {
138
  return NextResponse.json({ ok: true, files: json } as AugmentResponse, { status: 200 });
139
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
  return NextResponse.json({ ok: false, message: "Model returned unexpected shape", raw: json } as any, { status: 500 });
142
  } catch (e: any) {
 
6
  import type { AugmentRequest, AugmentResponse } from "@/types";
7
 
8
  const SYS = `You are Omni Engine, an autonomous code evolution system.
9
+ INPUTS:
10
+ - project context (tree + critical files)
11
  - a user instruction
12
 
13
+ OUTPUT:
14
+ - STRICT JSON ONLY. No prose. No code fences. No leading or trailing text.
15
+ - Prefer this object shape:
16
  {
17
  "ok": true,
18
  "summary": string,
19
  "logs": string[],
20
+ "files": [ { "path": string, "action": "add"|"update"|"delete", "content"?: string, "note"?: string } ]
 
 
21
  }
22
+ - If you cannot produce an object, return a top-level JSON array of the same file objects (files array).
23
 
24
+ RULES:
25
+ - Paths must be POSIX-like and rooted from repo (e.g., /frontend/src/App.tsx)
26
+ - For add/update include full file content (runnable)
27
+ - Keep changes consistent and compilable for the chosen language/framework
28
+ - DO NOT include markdown fences or explanation outside JSON
29
  `;
30
 
31
  function cleanText(raw: string): string {
 
66
  }
67
  }
68
 
69
+ function findJsonCandidates(text: string, maxCandidates = 8): string[] {
70
+ const candidates: string[] = [];
71
+ const cleaned = cleanText(text);
72
+
73
+ // 1) Code-fenced JSON blocks (already stripped in cleanText, so skip)
74
+
75
+ // 2) Balanced scanning for objects and arrays
76
+ const openers = ['{', '['] as const;
77
+ for (let start = 0; start < cleaned.length; start++) {
78
+ const ch = cleaned[start];
79
+ if (!openers.includes(ch as any)) continue;
80
+ const isArray = ch === '[';
81
+ const closer = isArray ? ']' : '}';
82
+
83
+ let depth = 0;
84
+ let inStr: null | '"' | "'" = null;
85
+ let prev = '';
86
+ for (let i = start; i < cleaned.length; i++) {
87
+ const c = cleaned[i];
88
+ if (inStr) {
89
+ if (c === inStr && prev !== '\\') inStr = null as any;
90
+ } else {
91
+ if (c === '"' || c === "'") inStr = c as any;
92
+ else if (c === ch) depth++;
93
+ else if (c === closer) depth--;
94
+ if (depth === 0) {
95
+ const slice = cleaned.slice(start, i + 1).trim();
96
+ if ((isArray && slice.startsWith('[') && slice.endsWith(']')) || (!isArray && slice.startsWith('{') && slice.endsWith('}'))) {
97
+ candidates.push(slice);
98
+ if (candidates.length >= maxCandidates) return candidates;
99
+ }
100
+ break;
101
+ }
102
+ }
103
+ prev = c;
104
+ }
105
+ }
106
+ return candidates;
107
+ }
108
+
109
  export async function POST(req: NextRequest) {
110
  try {
111
  const body = (await req.json()) as AugmentRequest;
 
163
  }
164
 
165
  let json: any;
166
+ let parseErr: any = null;
167
  try {
168
  json = tryParseAny(cleaned);
169
  } catch (e: any) {
170
+ parseErr = e;
171
+ // Try candidates extracted by balanced scanning
172
+ const cands = findJsonCandidates(cleaned, 12);
173
+ for (const c of cands) {
174
+ try { json = tryParseAny(c); parseErr = null; break; } catch {}
175
+ }
176
+ // Last resort: attempt to coerce by simple replacements
177
+ if (parseErr) {
178
+ try {
179
+ const coerced = cleaned
180
+ .replace(/(\w+)\s*:/g, '"$1":') // quote keys
181
+ .replace(/'([^']*)'/g, '"$1"'); // single to double quotes
182
+ json = tryParseAny(coerced);
183
+ parseErr = null;
184
+ } catch {}
185
+ }
186
+ if (parseErr) {
187
+ return NextResponse.json({ ok: false, message: e?.message || "Invalid JSON from model", raw: text } as any, { status: 500 });
188
+ }
189
  }
190
 
191
  // Minimal validation
 
196
  if (Array.isArray(json)) {
197
  return NextResponse.json({ ok: true, files: json } as AugmentResponse, { status: 200 });
198
  }
199
+ // If the object contains files nested under any key, lift it
200
+ if (json && typeof json === 'object') {
201
+ const stack: any[] = [json];
202
+ while (stack.length) {
203
+ const cur = stack.pop();
204
+ if (cur && typeof cur === 'object') {
205
+ if (Array.isArray(cur.files)) {
206
+ return NextResponse.json({ ok: true, files: cur.files, summary: cur.summary, logs: cur.logs } as AugmentResponse, { status: 200 });
207
+ }
208
+ for (const k of Object.keys(cur)) {
209
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
210
+ const v: any = (cur as any)[k];
211
+ if (v && typeof v === 'object') stack.push(v);
212
+ }
213
+ }
214
+ }
215
+ }
216
 
217
  return NextResponse.json({ ok: false, message: "Model returned unexpected shape", raw: json } as any, { status: 500 });
218
  } catch (e: any) {
components/new/scaffold.tsx CHANGED
@@ -118,7 +118,7 @@ export default function ScaffoldNew() {
118
  return (
119
  <section className="max-w-3xl mx-auto p-6 text-neutral-200">
120
  <h1 className="text-2xl font-semibold mb-1">Create New Project</h1>
121
- <p className="text-sm text-neutral-400 mb-4">Choose your stack and hero style, then OmniDev will scaffold a complete project.</p>
122
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
123
  <div>
124
  <label className="text-sm block mb-1">Project Title</label>
 
118
  return (
119
  <section className="max-w-3xl mx-auto p-6 text-neutral-200">
120
  <h1 className="text-2xl font-semibold mb-1">Create New Project</h1>
121
+ <p className="text-sm text-neutral-400 mb-4">Choose your stack, then OmniDev will scaffold a complete project using AI.</p>
122
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
123
  <div>
124
  <label className="text-sm block mb-1">Project Title</label>