BeastGokul commited on
Commit
aeeebcf
·
verified ·
1 Parent(s): 76c79e0

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +504 -0
app.py ADDED
@@ -0,0 +1,504 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ from dataclasses import dataclass, asdict, field
4
+ from typing import Optional, List
5
+
6
+ import gradio as gr
7
+ from openai import OpenAI
8
+
9
+ # ============================================================
10
+ # CONFIG
11
+ # ============================================================
12
+
13
+ OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
14
+
15
+ if not OPENROUTER_API_KEY:
16
+ raise RuntimeError(
17
+ "OPENROUTER_API_KEY environment variable not found."
18
+ )
19
+
20
+ MODEL = os.getenv(
21
+ "OPENROUTER_MODEL",
22
+ "openai/gpt-oss-120b:free"
23
+ )
24
+
25
+ client = OpenAI(
26
+ base_url="https://openrouter.ai/api/v1",
27
+ api_key=OPENROUTER_API_KEY
28
+ )
29
+
30
+ # ============================================================
31
+ # STATE
32
+ # ============================================================
33
+
34
+ @dataclass
35
+ class AgentState:
36
+ name: Optional[str] = None
37
+ role: Optional[str] = None
38
+ goal: Optional[str] = None
39
+ greeting: Optional[str] = None
40
+ tone: Optional[str] = None
41
+ memory: Optional[str] = None
42
+ audience: Optional[str] = None
43
+ domain: Optional[str] = None
44
+
45
+ tools: List[str] = field(default_factory=list)
46
+ policies: List[str] = field(default_factory=list)
47
+
48
+ def to_dict(self):
49
+ return asdict(self)
50
+
51
+ # ============================================================
52
+ # PROMPTS
53
+ # ============================================================
54
+
55
+ DISCOVERY_PROMPT = """
56
+ You are an Agent Architect.
57
+
58
+ Your job is to help users create AI agents entirely through conversation.
59
+
60
+ Rules:
61
+
62
+ - Talk naturally.
63
+ - Gather requirements progressively.
64
+ - Ask only ONE important follow-up question.
65
+ - Never mention prompts.
66
+ - Never mention JSON.
67
+ - Never mention implementation.
68
+ - Focus on understanding the user's vision.
69
+
70
+ The user's natural language is the source of truth.
71
+ """
72
+
73
+ ARCHITECT_PROMPT = """
74
+ Extract structured information from the user's message.
75
+
76
+ Return ONLY JSON.
77
+
78
+ Schema:
79
+
80
+ {
81
+ "name": null,
82
+ "role": null,
83
+ "goal": null,
84
+ "greeting": null,
85
+ "tone": null,
86
+ "memory": null,
87
+ "audience": null,
88
+ "domain": null,
89
+ "tools": [],
90
+ "policies": []
91
+ }
92
+ """
93
+
94
+ CAPABILITY_PROMPT = """
95
+ You are a Capability Planner.
96
+
97
+ Given an agent specification,
98
+ suggest useful capabilities.
99
+
100
+ Return ONLY JSON.
101
+
102
+ {
103
+ "tools": []
104
+ }
105
+ """
106
+
107
+ COMPILER_PROMPT = """
108
+ You generate system prompts.
109
+
110
+ Convert the specification into
111
+ a production-grade runtime prompt.
112
+
113
+ Output ONLY the prompt.
114
+ """
115
+
116
+ # ============================================================
117
+ # ORCHESTRATOR
118
+ # ============================================================
119
+
120
+ class AgentOrchestrator:
121
+
122
+ def __init__(self):
123
+ self.state = AgentState()
124
+ self.runtime_prompt = ""
125
+
126
+ # ========================================================
127
+
128
+ def llm(
129
+ self,
130
+ messages,
131
+ max_tokens=500,
132
+ response_format=None
133
+ ):
134
+
135
+ kwargs = {
136
+ "model": MODEL,
137
+ "messages": messages,
138
+ "max_tokens": max_tokens
139
+ }
140
+
141
+ if response_format:
142
+ kwargs["response_format"] = response_format
143
+
144
+ response = client.chat.completions.create(**kwargs)
145
+
146
+ content = response.choices[0].message.content
147
+
148
+ if not content:
149
+ return ""
150
+
151
+ return content.strip()
152
+
153
+ # ========================================================
154
+
155
+ def update_architecture(
156
+ self,
157
+ user_message: str
158
+ ):
159
+
160
+ try:
161
+
162
+ result = self.llm(
163
+ [
164
+ {
165
+ "role": "system",
166
+ "content": ARCHITECT_PROMPT
167
+ },
168
+ {
169
+ "role": "user",
170
+ "content": user_message
171
+ }
172
+ ],
173
+ response_format={
174
+ "type": "json_object"
175
+ }
176
+ )
177
+
178
+ data = json.loads(result)
179
+
180
+ for key, value in data.items():
181
+
182
+ if value in [None, "", []]:
183
+ continue
184
+
185
+ if hasattr(self.state, key):
186
+ setattr(
187
+ self.state,
188
+ key,
189
+ value
190
+ )
191
+
192
+ except Exception as e:
193
+ print("Architect error:", e)
194
+
195
+ # ========================================================
196
+
197
+ def update_capabilities(self):
198
+
199
+ try:
200
+
201
+ result = self.llm(
202
+ [
203
+ {
204
+ "role": "system",
205
+ "content": CAPABILITY_PROMPT
206
+ },
207
+ {
208
+ "role": "user",
209
+ "content": json.dumps(
210
+ self.state.to_dict(),
211
+ indent=2
212
+ )
213
+ }
214
+ ],
215
+ response_format={
216
+ "type": "json_object"
217
+ }
218
+ )
219
+
220
+ data = json.loads(result)
221
+
222
+ tools = data.get("tools", [])
223
+
224
+ if isinstance(tools, list):
225
+
226
+ merged = set(
227
+ self.state.tools
228
+ )
229
+
230
+ merged.update(tools)
231
+
232
+ self.state.tools = list(
233
+ merged
234
+ )
235
+
236
+ except Exception as e:
237
+ print("Capability error:", e)
238
+
239
+ # ========================================================
240
+
241
+ def compile_runtime_prompt(self):
242
+
243
+ try:
244
+
245
+ self.runtime_prompt = self.llm(
246
+ [
247
+ {
248
+ "role": "system",
249
+ "content": COMPILER_PROMPT
250
+ },
251
+ {
252
+ "role": "user",
253
+ "content": json.dumps(
254
+ self.state.to_dict(),
255
+ indent=2
256
+ )
257
+ }
258
+ ],
259
+ max_tokens=700
260
+ )
261
+
262
+ except Exception as e:
263
+
264
+ print("Compile error:", e)
265
+
266
+ # ========================================================
267
+
268
+ def developer_chat(
269
+ self,
270
+ message: str
271
+ ):
272
+
273
+ self.update_architecture(message)
274
+
275
+ self.update_capabilities()
276
+
277
+ self.compile_runtime_prompt()
278
+
279
+ reply = self.llm(
280
+ [
281
+ {
282
+ "role": "system",
283
+ "content": DISCOVERY_PROMPT
284
+ },
285
+ {
286
+ "role": "user",
287
+ "content":
288
+ f"""
289
+ Agent State:
290
+
291
+ {json.dumps(self.state.to_dict(), indent=2)}
292
+
293
+ Developer Message:
294
+
295
+ {message}
296
+ """
297
+ }
298
+ ],
299
+ max_tokens=250
300
+ )
301
+
302
+ return reply
303
+
304
+ # ========================================================
305
+
306
+ def client_chat(
307
+ self,
308
+ message,
309
+ history
310
+ ):
311
+
312
+ if not self.runtime_prompt:
313
+ self.compile_runtime_prompt()
314
+
315
+ messages = [
316
+ {
317
+ "role": "system",
318
+ "content": self.runtime_prompt
319
+ }
320
+ ]
321
+
322
+ for item in history:
323
+
324
+ messages.append(
325
+ {
326
+ "role": item["role"],
327
+ "content": item["content"]
328
+ }
329
+ )
330
+
331
+ messages.append(
332
+ {
333
+ "role": "user",
334
+ "content": message
335
+ }
336
+ )
337
+
338
+ return self.llm(
339
+ messages,
340
+ max_tokens=700
341
+ )
342
+
343
+ # ============================================================
344
+ # APP STATE
345
+ # ============================================================
346
+
347
+ orchestrator = AgentOrchestrator()
348
+
349
+ # ============================================================
350
+ # UI CALLBACK
351
+ # ============================================================
352
+
353
+ def chat_handler(
354
+ message,
355
+ history,
356
+ mode
357
+ ):
358
+
359
+ history = history or []
360
+
361
+ if mode == "Developer":
362
+
363
+ reply = orchestrator.developer_chat(
364
+ message
365
+ )
366
+
367
+ else:
368
+
369
+ reply = orchestrator.client_chat(
370
+ message,
371
+ history
372
+ )
373
+
374
+ history.append(
375
+ {
376
+ "role": "user",
377
+ "content": message
378
+ }
379
+ )
380
+
381
+ history.append(
382
+ {
383
+ "role": "assistant",
384
+ "content": reply
385
+ }
386
+ )
387
+
388
+ state = orchestrator.state.to_dict()
389
+
390
+ return (
391
+ "",
392
+ history,
393
+ state.get("name") or "",
394
+ state.get("role") or "",
395
+ state.get("goal") or "",
396
+ state.get("greeting") or "",
397
+ state.get("memory") or "",
398
+ state.get("tone") or "",
399
+ ", ".join(state.get("tools", [])),
400
+ orchestrator.runtime_prompt
401
+ )
402
+
403
+ # ============================================================
404
+ # UI
405
+ # ============================================================
406
+
407
+ with gr.Blocks(
408
+ title="Agent Platform",
409
+ fill_height=True
410
+ ) as demo:
411
+
412
+ gr.Markdown("# Agent Platform")
413
+
414
+ with gr.Row():
415
+
416
+ # LEFT PANEL
417
+ with gr.Column(scale=2):
418
+
419
+ mode = gr.Dropdown(
420
+ choices=[
421
+ "Developer",
422
+ "Client"
423
+ ],
424
+ value="Developer",
425
+ label="Mode"
426
+ )
427
+
428
+ chatbot = gr.Chatbot(
429
+ type="messages",
430
+ height=700
431
+ )
432
+
433
+ message = gr.Textbox(
434
+ placeholder="Describe your agent..."
435
+ )
436
+
437
+ # RIGHT PANEL
438
+ with gr.Column(scale=1):
439
+
440
+ gr.Markdown("## Agent Definition")
441
+
442
+ name = gr.Textbox(
443
+ label="Name"
444
+ )
445
+
446
+ role = gr.Textbox(
447
+ label="Role"
448
+ )
449
+
450
+ goal = gr.Textbox(
451
+ label="Goal"
452
+ )
453
+
454
+ greeting = gr.Textbox(
455
+ label="Greeting"
456
+ )
457
+
458
+ memory = gr.Textbox(
459
+ label="Memory"
460
+ )
461
+
462
+ tone = gr.Textbox(
463
+ label="Tone"
464
+ )
465
+
466
+ tools = gr.Textbox(
467
+ label="Tools"
468
+ )
469
+
470
+ runtime_prompt = gr.Textbox(
471
+ label="Compiled Runtime Prompt",
472
+ lines=18
473
+ )
474
+
475
+ message.submit(
476
+ chat_handler,
477
+ inputs=[
478
+ message,
479
+ chatbot,
480
+ mode
481
+ ],
482
+ outputs=[
483
+ message,
484
+ chatbot,
485
+ name,
486
+ role,
487
+ goal,
488
+ greeting,
489
+ memory,
490
+ tone,
491
+ tools,
492
+ runtime_prompt
493
+ ]
494
+ )
495
+
496
+ # ============================================================
497
+ # RUN
498
+ # ============================================================
499
+
500
+ if __name__ == "__main__":
501
+ demo.launch(
502
+ share=True,
503
+ debug=True
504
+ )