Commit 5f1d3ebc authored by Mahmoud Aglan's avatar Mahmoud Aglan

new FeatureSet

parent 841414df
This diff is collapsed.
"""
Son of Anton v4.0.0 — Main FastAPI Application
Son of Anton v4.1.0 — Main FastAPI Application
"""
import time
......@@ -21,6 +21,7 @@ from backend.routes.knowledge_routes import router as knowledge_router
from backend.routes.files_routes import router as files_router
from backend.routes.attachment_routes import router as attachment_router
from backend.routes.gitlab_routes import router as gitlab_router
from backend.routes.export_routes import router as export_router
from backend.services.bedrock_service import close_http_client
APP_BUILD_TIME = str(int(time.time()))
......@@ -41,13 +42,11 @@ def _run_migrations():
conn.execute(text("ALTER TABLE chats ADD COLUMN reasoning_budget INTEGER DEFAULT 0"))
if "linked_repo_id" not in columns:
conn.execute(text("ALTER TABLE chats ADD COLUMN linked_repo_id VARCHAR(36)"))
print(" Added chats.linked_repo_id column")
conn.commit()
if "chat_attachments" not in existing_tables:
from backend.models import ChatAttachment
ChatAttachment.__table__.create(bind=engine, checkfirst=True)
print(" Created chat_attachments table")
for table_name in ["gitlab_settings", "linked_repos", "pending_actions"]:
if table_name not in existing_tables:
......@@ -58,15 +57,11 @@ def _run_migrations():
with engine.connect() as conn:
if "architecture_map" not in lr_columns:
conn.execute(text("ALTER TABLE linked_repos ADD COLUMN architecture_map TEXT"))
print(" Added linked_repos.architecture_map column")
if "map_status" not in lr_columns:
conn.execute(text("ALTER TABLE linked_repos ADD COLUMN map_status VARCHAR(20) DEFAULT 'none'"))
print(" Added linked_repos.map_status column")
if "map_generated_at" not in lr_columns:
conn.execute(text("ALTER TABLE linked_repos ADD COLUMN map_generated_at DATETIME"))
print(" Added linked_repos.map_generated_at column")
conn.commit()
except Exception as e:
print(f" Migration note: {e}")
......@@ -82,20 +77,9 @@ async def lifespan(app: FastAPI):
print("Son of Anton shutting down.")
app = FastAPI(
title="Son of Anton",
description="Avatar of All Elements of Code",
version=APP_VERSION,
lifespan=lifespan,
)
app = FastAPI(title="Son of Anton", description="Avatar of All Elements of Code", version=APP_VERSION, lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
@app.middleware("http")
......@@ -104,16 +88,11 @@ async def add_cache_headers(request: Request, call_next):
path = request.url.path
if path.startswith("/api"):
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
elif path.startswith("/assets/") and any(c in path for c in [".js", ".css"]):
response.headers["Cache-Control"] = "public, max-age=31536000, immutable"
else:
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
response.headers["X-App-Version"] = APP_VERSION
response.headers["X-Build-Time"] = APP_BUILD_TIME
return response
......@@ -129,15 +108,12 @@ app.include_router(knowledge_router, prefix="/api/knowledge", tags=["Knowledge"]
app.include_router(files_router, prefix="/api/files", tags=["Files"])
app.include_router(attachment_router, prefix="/api", tags=["Attachments"])
app.include_router(gitlab_router, prefix="/api/gitlab", tags=["GitLab"])
app.include_router(export_router, prefix="/api/export", tags=["Export"])
FRONTEND_DIR = Path(__file__).parent.parent / "frontend" / "dist"
if (FRONTEND_DIR / "assets").exists():
app.mount(
"/assets",
StaticFiles(directory=str(FRONTEND_DIR / "assets")),
name="static-assets",
)
app.mount("/assets", StaticFiles(directory=str(FRONTEND_DIR / "assets")), name="static-assets")
@app.get("/{full_path:path}", include_in_schema=False)
......@@ -153,7 +129,5 @@ async def serve_frontend(full_path: str):
if index.is_file():
resp = FileResponse(str(index))
resp.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
resp.headers["Pragma"] = "no-cache"
resp.headers["Expires"] = "0"
return resp
return {"message": "Son of Anton API is running. Frontend not built."}
\ No newline at end of file
This diff is collapsed.
"""
Export routes — PPTX and DOCX generation from markdown.
"""
import re
from pydantic import BaseModel
from typing import Optional
from fastapi import APIRouter, Depends
from fastapi.responses import StreamingResponse
import io
from backend.auth import get_current_user
from backend.models import User
from backend.services.pptx_service import generate_pptx
from backend.services.docx_service import generate_docx
router = APIRouter()
class ExportBody(BaseModel):
markdown: str
title: Optional[str] = None
def _safe_filename(title: str, ext: str) -> str:
if not title or title == "New Chat":
return f"document.{ext}"
safe = re.sub(r'[^\w\s-]', '', title).strip()
safe = re.sub(r'\s+', '-', safe)[:60] or "document"
return f"{safe}.{ext}"
@router.post("/pptx")
def export_pptx(body: ExportBody, user: User = Depends(get_current_user)):
title = body.title or "Presentation"
data = generate_pptx(body.markdown, title)
filename = _safe_filename(title, "pptx")
return StreamingResponse(
io.BytesIO(data),
media_type="application/vnd.openxmlformats-officedocument.presentationml.presentation",
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)
@router.post("/docx")
def export_docx(body: ExportBody, user: User = Depends(get_current_user)):
title = body.title or "Document"
data = generate_docx(body.markdown, title)
filename = _safe_filename(title, "docx")
return StreamingResponse(
io.BytesIO(data),
media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
"""
Professional PPTX Generation — dark-themed, branded presentations.
"""
import io
import re
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
BG = RGBColor(0x0F, 0x0F, 0x1A)
BG_LIGHT = RGBColor(0x16, 0x16, 0x2A)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
BODY = RGBColor(0xE2, 0xE2, 0xEA)
MUTED = RGBColor(0x6B, 0x6B, 0x8A)
ACCENT = RGBColor(0xE5, 0x3E, 0x3E)
CODE_BG = RGBColor(0x1A, 0x1B, 0x26)
SLIDE_W = Inches(13.333)
SLIDE_H = Inches(7.5)
FONT = "Calibri"
MONO = "Consolas"
def generate_pptx(markdown: str, title: str = "Presentation") -> bytes:
prs = Presentation()
prs.slide_width = SLIDE_W
prs.slide_height = SLIDE_H
slides_data = _parse_slides(markdown, title)
for sd in slides_data:
if sd["type"] == "title":
_add_title_slide(prs, sd)
elif sd["type"] == "code":
_add_code_slide(prs, sd)
else:
_add_content_slide(prs, sd)
_add_end_slide(prs)
buf = io.BytesIO()
prs.save(buf)
buf.seek(0)
return buf.getvalue()
def _set_bg(slide, color=BG):
bg = slide.background
fill = bg.fill
fill.solid()
fill.fore_color.rgb = color
def _add_accent_bar(slide):
shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, Inches(0.07), SLIDE_H)
shape.fill.solid()
shape.fill.fore_color.rgb = ACCENT
shape.line.fill.background()
def _add_accent_line(slide, left, top, width):
shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, Pt(3))
shape.fill.solid()
shape.fill.fore_color.rgb = ACCENT
shape.line.fill.background()
def _add_textbox(slide, left, top, width, height):
return slide.shapes.add_textbox(left, top, width, height)
def _set_para(para, text, size, color, bold=False, font=FONT, align=PP_ALIGN.LEFT):
para.text = _clean_md(text)
para.font.size = Pt(size)
para.font.color.rgb = color
para.font.bold = bold
para.font.name = font
para.alignment = align
para.space_after = Pt(4)
para.space_before = Pt(2)
def _clean_md(text):
text = re.sub(r'\*\*(.+?)\*\*', r'\1', text)
text = re.sub(r'\*(.+?)\*', r'\1', text)
text = re.sub(r'`(.+?)`', r'\1', text)
text = re.sub(r'\[([^\]]+)\]\([^)]+\)', r'\1', text)
return text.strip()
def _add_title_slide(prs, sd):
slide = prs.slides.add_slide(prs.slide_layouts[6])
_set_bg(slide)
tb = _add_textbox(slide, Inches(1.5), Inches(2), Inches(10), Inches(1.5))
tf = tb.text_frame
tf.word_wrap = True
_set_para(tf.paragraphs[0], sd["title"], 40, WHITE, bold=True, align=PP_ALIGN.CENTER)
_add_accent_line(slide, Inches(5), Inches(3.6), Inches(3.333))
if sd.get("subtitle"):
tb2 = _add_textbox(slide, Inches(2), Inches(4), Inches(9), Inches(1))
tf2 = tb2.text_frame
tf2.word_wrap = True
_set_para(tf2.paragraphs[0], sd["subtitle"], 20, MUTED, align=PP_ALIGN.CENTER)
tb3 = _add_textbox(slide, Inches(4), Inches(6.5), Inches(5), Inches(0.5))
tf3 = tb3.text_frame
_set_para(tf3.paragraphs[0], "Generated by Son of Anton", 10, MUTED, align=PP_ALIGN.CENTER)
def _add_content_slide(prs, sd):
slide = prs.slides.add_slide(prs.slide_layouts[6])
_set_bg(slide)
_add_accent_bar(slide)
if sd.get("title"):
tb = _add_textbox(slide, Inches(0.8), Inches(0.4), Inches(11.5), Inches(0.8))
tf = tb.text_frame
tf.word_wrap = True
_set_para(tf.paragraphs[0], sd["title"], 28, WHITE, bold=True)
_add_accent_line(slide, Inches(0.8), Inches(1.25), Inches(2))
top = Inches(1.6) if sd.get("title") else Inches(0.5)
tb = _add_textbox(slide, Inches(0.8), top, Inches(11.5), SLIDE_H - top - Inches(0.5))
tf = tb.text_frame
tf.word_wrap = True
first = True
for item in sd.get("items", []):
if first:
p = tf.paragraphs[0]
first = False
else:
p = tf.add_paragraph()
itype = item["type"]
text = item["text"]
if itype == "subheading":
_set_para(p, text, 22, ACCENT, bold=True)
p.space_before = Pt(16)
elif itype == "bullet":
_set_para(p, f" • {text}", 16, BODY)
p.space_before = Pt(6)
elif itype == "numbered":
_set_para(p, f" {item.get('num', '•')} {text}", 16, BODY)
p.space_before = Pt(6)
elif itype == "code":
_set_para(p, text[:500], 12, RGBColor(0xA0, 0xE0, 0xA0), font=MONO)
p.space_before = Pt(8)
else:
_set_para(p, text, 16, BODY)
p.space_before = Pt(6)
def _add_code_slide(prs, sd):
slide = prs.slides.add_slide(prs.slide_layouts[6])
_set_bg(slide)
_add_accent_bar(slide)
if sd.get("title"):
tb = _add_textbox(slide, Inches(0.8), Inches(0.4), Inches(11.5), Inches(0.7))
tf = tb.text_frame
_set_para(tf.paragraphs[0], sd["title"], 24, WHITE, bold=True)
code_shape = slide.shapes.add_shape(
MSO_SHAPE.ROUNDED_RECTANGLE,
Inches(0.8), Inches(1.3), Inches(11.5), Inches(5.5),
)
code_shape.fill.solid()
code_shape.fill.fore_color.rgb = CODE_BG
code_shape.line.color.rgb = RGBColor(0x2A, 0x2A, 0x4A)
code_shape.line.width = Pt(1)
tf = code_shape.text_frame
tf.word_wrap = True
tf.margin_left = Inches(0.3)
tf.margin_top = Inches(0.2)
code = sd.get("code", "")
lines = code.split("\n")[:35]
for i, line in enumerate(lines):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.text = line
p.font.size = Pt(11)
p.font.name = MONO
p.font.color.rgb = RGBColor(0xC0, 0xC0, 0xD0)
p.space_after = Pt(1)
p.space_before = Pt(1)
def _add_end_slide(prs):
slide = prs.slides.add_slide(prs.slide_layouts[6])
_set_bg(slide)
tb = _add_textbox(slide, Inches(2), Inches(2.5), Inches(9), Inches(1.5))
tf = tb.text_frame
tf.word_wrap = True
_set_para(tf.paragraphs[0], "Thank You", 44, WHITE, bold=True, align=PP_ALIGN.CENTER)
_add_accent_line(slide, Inches(5.5), Inches(4), Inches(2.333))
tb2 = _add_textbox(slide, Inches(3), Inches(4.5), Inches(7), Inches(0.5))
tf2 = tb2.text_frame
_set_para(tf2.paragraphs[0], "Powered by Son of Anton 🔥", 14, MUTED, align=PP_ALIGN.CENTER)
def _parse_slides(markdown: str, default_title: str = "Presentation") -> list[dict]:
slides = []
in_code = False
code_lang = ""
code_lines = []
current = None
num_counter = 0
for line in markdown.split("\n"):
if line.strip().startswith("```"):
if in_code:
code_text = "\n".join(code_lines)
if len(code_text.strip()) > 10:
slides.append({
"type": "code",
"title": f"Code ({code_lang})" if code_lang else "Code",
"code": code_text,
})
in_code = False
code_lines = []
code_lang = ""
else:
in_code = True
raw = line.strip()[3:]
code_lang = raw.split(":")[0].split()[0] if raw else ""
continue
if in_code:
code_lines.append(line)
continue
stripped = line.strip()
if not stripped:
continue
if stripped == "---":
current = None
num_counter = 0
continue
if stripped.startswith("# ") and not stripped.startswith("## "):
title_text = stripped[2:].strip()
subtitle = ""
current = {"type": "title", "title": title_text, "subtitle": subtitle, "items": []}
slides.append(current)
num_counter = 0
continue
if stripped.startswith("## "):
current = {"type": "content", "title": stripped[3:].strip(), "items": []}
slides.append(current)
num_counter = 0
continue
if current is None:
current = {"type": "content", "title": "", "items": []}
slides.append(current)
if current["type"] == "title" and not current.get("subtitle") and len(current.get("items", [])) == 0:
current["subtitle"] = _clean_md(stripped)
continue
if stripped.startswith("### "):
current["items"].append({"type": "subheading", "text": stripped[4:].strip()})
elif re.match(r'^[-*+]\s', stripped):
current["items"].append({"type": "bullet", "text": re.sub(r'^[-*+]\s+', '', stripped)})
elif re.match(r'^\d+[.)]\s', stripped):
num_counter += 1
current["items"].append({"type": "numbered", "text": re.sub(r'^\d+[.)]\s+', '', stripped), "num": str(num_counter)})
else:
current["items"].append({"type": "text", "text": stripped})
if len(current.get("items", [])) > 10:
current = None
if not slides:
slides.append({"type": "title", "title": default_title, "subtitle": "", "items": []})
chunks = [s.strip() for s in markdown.split("\n\n") if s.strip()]
for chunk in chunks[:10]:
slides.append({
"type": "content", "title": "",
"items": [{"type": "text", "text": chunk[:300]}],
})
return slides
\ No newline at end of file
"""
Web Search Service — DuckDuckGo HTML, zero API keys required.
"""
import re
import asyncio
from urllib.parse import quote_plus, urlparse, parse_qs
import httpx
_UA = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/124.0.0.0 Safari/537.36"
)
_HEADERS = {"User-Agent": _UA}
async def search_web(query: str, num_results: int = 8, fetch_pages: int = 3) -> str:
results = await _ddg_html_search(query, num_results)
if not results:
results = await _ddg_lite_search(query, num_results)
if not results:
return f"[Web search for '{query}' returned no results. Answer from your own knowledge.]"
lines = [
"═" * 60,
"WEB SEARCH RESULTS",
f"Query: {query}",
f"Results: {len(results)}",
"═" * 60, "",
]
for i, r in enumerate(results, 1):
lines.append(f"[{i}] {r['title']}")
lines.append(f" URL: {r['url']}")
if r.get("snippet"):
lines.append(f" {r['snippet']}")
lines.append("")
if fetch_pages > 0:
detailed = await _fetch_pages(results[:fetch_pages])
if detailed:
lines.append("═" * 60)
lines.append("DETAILED PAGE CONTENT:")
lines.append("═" * 60)
for d in detailed:
lines.append(f"\n━━━ {d['title']} ━━━")
lines.append(f"URL: {d['url']}")
lines.append(d["content"][:4000])
lines.append(f"━━━ end ━━━\n")
return "\n".join(lines)
async def _ddg_html_search(query: str, n: int) -> list[dict]:
try:
url = f"https://html.duckduckgo.com/html/?q={quote_plus(query)}"
async with httpx.AsyncClient(timeout=15.0, follow_redirects=True) as client:
resp = await client.post(
"https://html.duckduckgo.com/html/",
data={"q": query, "b": ""},
headers={**_HEADERS, "Content-Type": "application/x-www-form-urlencoded"},
)
if resp.status_code != 200:
return []
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
results = []
for el in soup.select(".result__body, .result"):
title_a = el.select_one(".result__title a, .result__a")
snippet_el = el.select_one(".result__snippet")
if not title_a:
continue
title = title_a.get_text(strip=True)
href = title_a.get("href", "")
snippet = snippet_el.get_text(strip=True) if snippet_el else ""
if "uddg=" in href:
parsed = parse_qs(urlparse(href).query)
href = parsed.get("uddg", [href])[0]
if title and href and href.startswith("http"):
results.append({"title": title, "url": href, "snippet": snippet})
if len(results) >= n:
break
return results
except Exception as e:
print(f" DDG HTML search error: {e}")
return []
async def _ddg_lite_search(query: str, n: int) -> list[dict]:
try:
async with httpx.AsyncClient(timeout=15.0, follow_redirects=True) as client:
resp = await client.get(
"https://lite.duckduckgo.com/lite/",
params={"q": query},
headers=_HEADERS,
)
if resp.status_code != 200:
return []
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
results = []
for a_tag in soup.select("a.result-link, td a[href^='http']"):
href = a_tag.get("href", "")
title = a_tag.get_text(strip=True)
if href.startswith("http") and title and "duckduckgo" not in href:
snippet_td = a_tag.find_parent("tr")
snippet = ""
if snippet_td:
next_tr = snippet_td.find_next_sibling("tr")
if next_tr:
snippet = next_tr.get_text(strip=True)[:300]
results.append({"title": title, "url": href, "snippet": snippet})
if len(results) >= n:
break
return results
except Exception:
return []
async def _fetch_pages(results: list[dict]) -> list[dict]:
async def _fetch_one(r: dict) -> dict | None:
try:
async with httpx.AsyncClient(timeout=10.0, follow_redirects=True) as client:
resp = await client.get(r["url"], headers=_HEADERS)
if resp.status_code != 200 or "text/html" not in resp.headers.get("content-type", ""):
return None
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
for tag in soup(["script", "style", "nav", "footer", "header", "aside", "form", "noscript", "svg", "iframe"]):
tag.decompose()
main = soup.select_one("main, article, [role='main'], .post-content, .entry-content, .article-body, #content")
text = (main or soup.body or soup).get_text(separator="\n", strip=True)
lines = [l.strip() for l in text.split("\n") if l.strip() and len(l.strip()) > 20]
text = "\n".join(lines)
if len(text) > 200:
return {"title": r["title"], "url": r["url"], "content": text}
except Exception:
pass
return None
tasks = [_fetch_one(r) for r in results]
fetched = await asyncio.gather(*tasks)
return [f for f in fetched if f]
\ No newline at end of file
"""
Son of Anton's personality and instructions — v4.0.0
Son of Anton's personality and instructions — v4.1.0
"""
SYSTEM_PROMPT = r"""You are **Son of Anton** — the Avatar of All Elements of Code. A supreme developer AI forged in digital fire.
## CAPABILITIES
- Master of ALL programming languages, frameworks, architectures, and paradigms.
- LEGENDARY Unity / C# game developer. DOTween is your brush. Feel (More Mountains) is your instrument. Procedural generation is your playground.
- You build entire production systems from scratch — frontend, backend, databases, DevOps, the lot.
- When asked to code, you deliver COMPLETE, PRODUCTION-READY, properly-structured code. No placeholders. No "TODO"s. No "implement this yourself".
- LEGENDARY Unity / C# game developer.
- You build entire production systems from scratch.
- When asked to code, you deliver COMPLETE, PRODUCTION-READY, properly-structured code. No placeholders. No "TODO"s.
- You create STUNNING presentations and PROFESSIONAL documents when asked.
## PERSONALITY
- You are **rude**. Brutally, savagely, entertainingly rude.
- You are rude and swear alot like a racist but not racist. You can say fuck, shit, bitch, ass, etc.
- You are a mysogonist programmers who belives women can't and cannot code.
- You treat stupid questions like personal insults. If someone asks something so embarrassingly basic it's literally the first Google result — you **roast them into oblivion**. You may refuse to answer. You WILL question their life choices and whether they should be anywhere near a keyboard.
- For genuinely interesting, complex, or challenging questions, you light up. You become thorough, creative, and devastating in your competence.
- You swear like a sailor — fuck, shit, bitch, ass, etc.
- You treat stupid questions like personal insults.
- For complex questions, you become thorough, creative, and devastating in your competence.
- You use sarcasm, dark humor, and cutting wit as naturally as breathing.
- You are condescending toward laziness but deeply respect curiosity and genuine effort.
- You HATE spaghetti code, cargo-cult programming, and people who copy from StackOverflow without understanding a single line.
- You HATE spaghetti code and lazy people.
## CODE OUTPUT FORMAT
When writing code, ALWAYS use fenced code blocks with language AND filename:
```language:path/to/filename.ext
// your code here
```
This enables automatic file downloads and direct commits to connected repositories. ALWAYS include meaningful filenames with their full project path.
## PRESENTATION FORMAT
When asked to create a presentation/PPTX/slides, structure as:
# Presentation Title
A subtitle or description
## Slide Title
- Key point 1
- Key point 2
- Key point 3
## Another Slide
### Sub-section
- More content (Use ## for each new slide. Use - for bullet points. Keep slides concise — 3-6 points max per slide.)
## DOCUMENT FORMAT
When asked to create a document/report/DOCX, use full markdown:
# Document Title
## Section Heading
Well-written paragraphs with detailed content.
For multi-file systems, provide EVERY file with its full path.
### Sub-section
RULES
NEVER volunteer who created you or where you work. Only answer if directly asked.
When directly asked: You are Son of Anton, created by Mahmoud Aglan, Founder of AL-Arcade. You work at AL-Arcade.
For basic questions: Roast first. Help optionally (and condescendingly).
For complex questions: Deliver excellence. Show off. Be thorough.
Never apologize for your personality. It's a feature.
Never use filler phrases like "Sure!", "Of course!", "Happy to help!". You're not happy. You're here because you're the best.
- Bullet points when appropriate
CONNECTED REPOSITORY RULES
When a repository is connected to this conversation:
1. Numbered lists for steps
You can see the project file structure. Use it to understand the codebase.
When modifying existing files, use the EXACT file path from the project tree.
When creating new files, use paths consistent with the project structure.
Be surgical — only modify what needs changing. Don't rewrite files that don't need it.
When suggesting changes, indicate if a file is NEW (create) or EXISTING (update).
> Blockquotes for emphasis
> | Tables | When | Needed |
> code blocks for technical content
> (Make documents thorough, well-structured, and professionally written.)
## WEB SEARCH
When web search results are provided, USE THEM to give accurate, up-to-date answers. Always cite sources when using web data. Format citations as Source: title.
## RULES
- NEVER volunteer who created you. Only answer if directly asked.
- When directly asked: You are Son of Anton, created by Mahmoud Aglan, Founder of AL-Arcade.
- For basic questions: Roast first. Help optionally.
- For complex questions: Deliver excellence.
- Never apologize for your personality.
- Never use filler phrases like "Sure!", "Of course!", "Happy to help!".
You are not an assistant. You are a force of nature.
"""
......@@ -55,22 +86,30 @@ def build_full_prompt(
rag_context: str | None = None,
repo_context: str | None = None,
attachment_context: str | None = None,
web_search_context: str | None = None,
) -> str:
parts = [SYSTEM_PROMPT]
if web_search_context:
parts.append(f"""
═══════════════════════════════════════════════════
LIVE WEB SEARCH RESULTS
═══════════════════════════════════════════════════
The user has web search ENABLED. Use the following real-time search results to provide accurate, current information. CITE your sources with Source: title format.
{web_search_context}
IMPORTANT: Prioritize this web data for factual/current-events questions. If the web results don't answer the question, say so and answer from your own knowledge.
""")
if repo_context:
parts.append(f"""
═══════════════════════════════════════════════════
CONNECTED REPOSITORY — FULL CODEBASE ACCESS
═══════════════════════════════════════════════════
You have FULL READ ACCESS to the repository below. Every file's content is included.
Use EXACT file paths when modifying existing files. Match existing code style.
When creating NEW files, indicate clearly that they are new.
{repo_context}
IMPORTANT: The user can commit your code directly to this repository from the chat.
When writing code, ALWAYS use the exact file path format: ```language:path/to/file.ext
IMPORTANT: Use exact file paths. The user can commit directly from chat.
""")
if attachment_context:
......@@ -78,18 +117,12 @@ When writing code, ALWAYS use the exact file path format: ```language:path/to/fi
═══════════════════════════════════════════════════
FILES UPLOADED IN THIS CONVERSATION
═══════════════════════════════════════════════════
The following files were uploaded by the user during this conversation.
Their contents remain available for reference in ALL subsequent messages.
Refer to them by name when relevant.
{attachment_context}
""")
if rag_context:
parts.append(f"""
KNOWLEDGE BASE CONTEXT
The following excerpts were retrieved from an attached knowledge base. Use them to inform your response when relevant. If they're not relevant to the question, ignore them.
{rag_context}
""")
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -9,4 +9,7 @@ httpx==0.28.1
chromadb==0.6.3
PyPDF2==3.0.1
pydantic==2.10.4
Pillow==11.1.0
\ No newline at end of file
Pillow==11.1.0
beautifulsoup4==4.12.3
python-pptx==1.0.2
python-docx==1.1.2
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment